Skip to content

Commit

Permalink
Linux support:
Browse files Browse the repository at this point in the history
* MPRIS interface for desktop media player integration with artwork URL
* Snap build with minimal permissions
* Application Icon
* Change in handling of menu shortcuts (needs testing on MacOS and Windows!)
  • Loading branch information
ponyfleisch committed Jun 9, 2020
1 parent 3067210 commit dfb5d63
Show file tree
Hide file tree
Showing 6 changed files with 466 additions and 40 deletions.
57 changes: 30 additions & 27 deletions app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ const darkMode = require('./dark-mode')
const dockMenu = require('./dock-menu')
const errorHandlers = require('./error-handlers')
const mainMenu = require('./menu')
const mpris = require('./mpris')
const options = require('./options')
const SoundCloud = require('./soundcloud')
const touchBarMenu = require('./touch-bar-menu')
const windowOpenPolicy = require('./window-open-policy')
const windowState = require('electron-window-state')
const path = require('path')

let mainWindow = null
let aboutWindow = null
Expand All @@ -42,13 +44,29 @@ if (userData) {
app.setPath('userData', app.getPath('userData') + ' ' + profile)
}

if (process.platform == 'linux') {
// see mpris.js for details
app.commandLine.appendSwitch('disable-features', 'MediaSessionService')
}

let quitting = false

app.on('before-quit', () => {
quitting = true
})

app.requestSingleInstanceLock()
if (!app.requestSingleInstanceLock()) {
app.quit()
}

app.on('second-instance', () => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})

app.on('ready', (event, argv) => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
Expand Down Expand Up @@ -94,7 +112,10 @@ app.on('ready', () => {
webPreferences: {
nodeIntegration: false,
preload: `${__dirname}/preload.js`
}
},
icon: `${path.dirname(
process.execPath
)}/usr/share/icons/hicolor/512x512/apps/soundcleod.png`
})

const soundcloud = new SoundCloud(mainWindow)
Expand All @@ -104,6 +125,8 @@ app.on('ready', () => {
if (process.platform == 'darwin') {
dockMenu(soundcloud)
touchBarMenu(mainWindow, soundcloud)
} else if (process.platform == 'linux') {
mpris(soundcloud)
}

mainWindowState.manage(mainWindow)
Expand All @@ -128,13 +151,6 @@ app.on('ready', () => {
}
})

// Only send commands from menu accelerators when the app is not focused.
// This avoids double-triggering actions and triggering actions during text
// is entered into the search input or in other places.
function isNotFocused() {
return !mainWindow || !mainWindow.isFocused()
}

mainWindow.on('closed', () => {
if (process.platform !== 'darwin') {
app.quit()
Expand All @@ -159,38 +175,25 @@ app.on('ready', () => {
}

menu.events.on('playPause', () => {
if (isNotFocused()) {
soundcloud.playPause()
}
soundcloud.playPause()
})

menu.events.on('likeUnlike', () => {
if (isNotFocused()) {
soundcloud.likeUnlike()
}
soundcloud.likeUnlike()
})

menu.events.on('repost', () => {
if (isNotFocused()) {
soundcloud.repost()
}
soundcloud.repost()
})

menu.events.on('nextTrack', () => {
if (isNotFocused()) {
soundcloud.nextTrack()
}
soundcloud.nextTrack()
})

menu.events.on('previousTrack', () => {
if (isNotFocused()) {
soundcloud.previousTrack()
}
soundcloud.previousTrack()
})

// The shortcuts *not* handled by SoundCloud itself
// don't need the isNotFocused() check to avoid double triggering

menu.events.on('home', () => {
soundcloud.goHome()
})
Expand Down
31 changes: 21 additions & 10 deletions app/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,41 +98,52 @@ function buildMenu(options) {
]
},
{
// ignore accelerators for these items as they are handled by soundcloud itself
label: 'Controls',
submenu: [
{
label: 'Play/Pause',
accelerator: 'Space',
click() {
events.emit('playPause')
click(menuItem, browserWindow, event) {
if (!event.triggeredByAccelerator) {
events.emit('playPause')
}
}
},
{
label: 'Like',
accelerator: 'L',
click() {
events.emit('likeUnlike')
click(menuItem, browserWindow, event) {
if (!event.triggeredByAccelerator) {
events.emit('likeUnlike')
}
}
},
{
label: 'Repost',
accelerator: 'R',
click() {
events.emit('repost')
click(menuItem, browserWindow, event) {
if (!event.triggeredByAccelerator) {
events.emit('repost')
}
}
},
{
label: 'Next',
accelerator: 'Shift+Right',
click() {
events.emit('nextTrack')
click(menuItem, browserWindow, event) {
if (!event.triggeredByAccelerator) {
events.emit('nextTrack')
}
}
},
{
label: 'Previous',
accelerator: 'Shift+Left',
click() {
events.emit('previousTrack')
click(menuItem, browserWindow, event) {
if (!event.triggeredByAccelerator) {
events.emit('previousTrack')
}
}
}
]
Expand Down
41 changes: 41 additions & 0 deletions app/mpris.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict'

// it's currently impossible to expose chrome's native media session interface
// when using snap because chrome does not allow setting the name of the session.
// hence we re-implement it here. As a bonus, we get artwork support.

const Player = require('mpris-service')

module.exports = function mpris(soundcloud) {
const player = Player({
name: 'soundcleod',
identity: 'Player for SoundCloud',
supportedInterfaces: ['player']
})

player.on('playpause', () => soundcloud.playPause())

player.on('next', () => soundcloud.nextTrack())

player.on('previous', () => soundcloud.previousTrack())

soundcloud.on('play-new-track', (metadata) => {
setMetadata(metadata)
})

soundcloud.on('play', () => {
player.playbackStatus = 'Playing'
})

soundcloud.on('pause', () => {
player.playbackStatus = 'Paused'
})

function setMetadata(metadata) {
player.metadata = {
'mpris:artUrl': metadata.artworkURL,
'xesam:title': metadata.title,
'xesam:artist': [metadata.subtitle]
}
}
}
Loading

0 comments on commit dfb5d63

Please sign in to comment.