Skip to content
This repository has been archived by the owner on Nov 22, 2021. It is now read-only.

Fix touchbar and add repost button to it. #233

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions app/context-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,32 @@

const electronContextMenu = require('electron-context-menu')

const { shell } = require('electron')

module.exports = function contextMenu(window, soundcloud) {
// TODO: apply context menu to all windows but only add navigation items to main window
// See https://github.com/sindresorhus/electron-context-menu/pull/25
electronContextMenu({
window,
prepend: (params) => {
prepend: (defaultActions, params) => {
if (params.mediaType == 'none') {
return menuTemplate(soundcloud)
}
}
},
append: (defaultActions, params) => [
{
label: 'Open in Browser',
after: ['copyLink'],
visible: params.linkURL.length !== 0 && params.mediaType === 'none',
click(menuItem) {
shell.openExternal(
menuItem.transform
? menuItem.transform(params.linkURL)
: params.linkURL
)
}
}
]
})
}

Expand Down
2 changes: 1 addition & 1 deletion app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ app.on('ready', () => {
contextMenu(mainWindow, soundcloud)
errorHandlers(mainWindow)
darkMode(mainWindow)
if (process.platform == 'darwin') {
if (process.platform === 'darwin') {
dockMenu(soundcloud)
touchBarMenu(mainWindow, soundcloud)
}
Expand Down
2 changes: 1 addition & 1 deletion app/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module.exports = function options(process, processArgv) {
return {
autoUpdaterBaseUrl: argv['auto-updater-base-url'],
baseUrl: argv['base-url'],
developerTools: argv['developer-tools'],
developerTools: true, // argv['developer-tools'],
launchUrl: isSoundcloudUrl(launchUrl) ? launchUrl : undefined,
profile: argv.profile,
quitAfterLastWindow: argv['quit-after-last-window'],
Expand Down
95 changes: 88 additions & 7 deletions app/preload.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { ipcRenderer } = require('electron')
const {ipcRenderer} = require('electron')

require('./macos-swipe-navigation').register()

Expand All @@ -9,13 +9,52 @@ if (process.env.SPECTRON) {
window.electronRequire = require
}

ipcRenderer.on('getTrackMetadata', ({ sender }) => sendTrackMetadata(sender))
let isReposted = false

function subtreeCallback(mutationList) {
mutationList.forEach((mutation) => {
// console.log(mutation)
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
if (mutation.target.className.indexOf('sc-button-repost') !== -1) {
const oldReposted = isReposted
isReposted = getReposted()
if (oldReposted === undefined || isReposted !== oldReposted) {
ipcRenderer.send('repost', {reposted: isReposted})
}
}
} else if (mutation.type === 'childList' && mutation.target !== undefined) {
if (mutation.target.id.indexOf('gritter-notice-wrapper') !== -1) {
// reposted popup
if (mutation.addedNodes.length > 0
&& mutation.addedNodes[0].innerText.indexOf('was reposted to')
!== -1) {
const oldReposted = isReposted
isReposted = true
if (oldReposted === undefined || isReposted !== oldReposted) {
ipcRenderer.send('repost', {reposted: isReposted})
}
}
}
}
})
}

const observer = new MutationObserver(subtreeCallback)
observer.observe(document, {
childList: true,
subtree: true,
attributes: true
})

ipcRenderer.on('getTrackMetadata', ({sender}) => sendTrackMetadata(sender))
ipcRenderer.on('navigate', (_, url) => navigate(url))
ipcRenderer.on('notification', (_, metadata) => showNotification(metadata))

function sendTrackMetadata(sender) {
const artworkURL = getArtworkURL()
sender.send('trackMetadata', { artworkURL })
const trackURL = getTrackURL()
isReposted = getReposted()
sender.send('trackMetadata', {artworkURL, trackURL, isReposted})
}

function navigate(url) {
Expand All @@ -38,18 +77,60 @@ function getArtworkURL() {
return null
}

const { Notification } = window
function getTrackURL() {
const track = document.querySelector('.playbackSoundBadge__titleLink')
if (track) {
const url = `https://soundcloud.com${track.getAttribute('href')}`
if (url.indexOf('?') === -1) {
return url
}
return url.split('?')[0]
}
return null
}

function getReposted() {
// get track from the track's page
const gritter = document.querySelector('.gritter-with-image p')
if (gritter != null) {
if (gritter.innerText.indexOf('was reposted to') !== -1) {
return true
}
}

let nowPlaying = document.querySelector('.listenEngagement__footer')
if (!nowPlaying) {
// get track from stream
nowPlaying = document.querySelector('.playing')
} else {
// on the track's main page, check if it's playing or not
const playButton = document.querySelector('.fullHero__title').querySelector(
'.sc-button-pause')
if (!playButton) {
return false
}
}
if (nowPlaying) {
const repostButton = nowPlaying.querySelector('.sc-button-repost')
if (repostButton) {
return repostButton.className.indexOf('sc-button-selected') !== -1
}
}
return false
}

const {Notification} = window
// Disable SoundCloud's own notifications, because:
// - They are not silent on macOS
// - They are hidden behind a feature flag
delete window.Notification

function showNotification({ title, body, icon }) {
function showNotification({title, body, icon}) {
/* eslint no-new: off */
new Notification(title, { body, icon, silent: true })
new Notification(title, {body, icon, silent: true})
}

const { confirm } = window
const {confirm} = window

window.confirm = (message) => {
// For some bizarre reason SoundCloud calls comfirm() with { string: 'The message' }
Expand Down
Binary file added app/res/ajax0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/ajax9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/repost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/res/reposted.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 15 additions & 8 deletions app/soundcloud.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { ipcMain } = require('electron')
const {ipcMain} = require('electron')
const Events = require('events')

module.exports = class SoundCloud extends Events {
Expand All @@ -12,6 +12,9 @@ module.exports = class SoundCloud extends Events {
window.webContents
.on('media-started-playing', onMediaStartedPlaying.bind(this))
.on('media-paused', onMediaPaused.bind(this))
ipcMain.on('repost', (event, args) => {
onMediaRepost(this, args)
})
fixFlakyMediaKeys(window)
}

Expand Down Expand Up @@ -98,12 +101,16 @@ function onMediaPaused() {
this.emit('pause')
}

function onMediaRepost(emitter, reposted) {
emitter.emit('repost', reposted)
}

function getTrackMetadata() {
return new Promise((resolve) => {
ipcMain.once('trackMetadata', (_, trackMetadata) => {
const title = parseTitle(this.window.getTitle())
if (title) {
resolve({ ...title, ...trackMetadata })
resolve({...title, ...trackMetadata})
} else {
resolve()
}
Expand All @@ -114,13 +121,13 @@ function getTrackMetadata() {

function parseTitle(windowTitle) {
let titleParts = windowTitle.split(' by ', 2)
if (titleParts.length == 1) {
if (titleParts.length === 1) {
titleParts = windowTitle.split(' in ', 2)
}
if (titleParts.length == 2) {
if (titleParts.length === 2) {
// Title has " in " in it when not playing but on a playlist page
const [title, subtitle] = titleParts
return { title, subtitle }
return {title, subtitle}
}
return null
}
Expand Down Expand Up @@ -148,8 +155,8 @@ function fixFlakyMediaKeys(mainWindow) {

function compareTrackMetadata(lhs, rhs) {
return (
lhs.title == rhs.title &&
lhs.subtitle == rhs.subtitle &&
lhs.artworkUrl == rhs.artworkUrl
lhs.title === rhs.title &&
lhs.subtitle === rhs.subtitle &&
lhs.artworkUrl === rhs.artworkUrl
)
}
Loading