mpris implementation, function cleanup

This commit is contained in:
Core 2021-12-27 11:56:00 +00:00
parent 8106f0ac2e
commit fe73e34833
5 changed files with 69 additions and 41 deletions

View file

@ -1,5 +1,5 @@
require('v8-compile-cache'); require('v8-compile-cache');
const { app, screen } = require('electron'); const { app } = require('electron');
// Analytics for debugging. // Analytics for debugging.
const ElectronSentry = require("@sentry/electron"); const ElectronSentry = require("@sentry/electron");
@ -72,6 +72,10 @@ function CreateWindow() {
/** CIDER **/ /** CIDER **/
} }
if (process.platform === "linux") {
app.commandLine.appendSwitch('disable-features', 'MediaSessionService');
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* App Event Handlers * App Event Handlers

View file

@ -5,10 +5,9 @@ const express = require("express");
const path = require("path"); const path = require("path");
const windowStateKeeper = require("electron-window-state"); const windowStateKeeper = require("electron-window-state");
const os = require('os'); const os = require('os');
const Store = require("electron-store");
const store = new Store();
const yt = require('youtube-search-without-api-key'); const yt = require('youtube-search-without-api-key');
const discord = require('./discordrpc'); const discord = require('./discordrpc');
const mpris = require('./mpris');
// Analytics for debugging. // Analytics for debugging.
const ElectronSentry = require("@sentry/electron"); const ElectronSentry = require("@sentry/electron");
@ -16,7 +15,7 @@ ElectronSentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.inge
const CiderBase = { const CiderBase = {
async Start() { async Start() {
this.clientPort = await getPort({port : 9000}); this.clientPort = await getPort({port: 9000});
this.CreateBrowserWindow() this.CreateBrowserWindow()
}, },
clientPort: 0, clientPort: 0,
@ -39,7 +38,7 @@ const CiderBase = {
frame: false, frame: false,
title: "Cider", title: "Cider",
vibrancy: 'dark', vibrancy: 'dark',
// transparent: true, // transparent: true,
hasShadow: false, hasShadow: false,
webPreferences: { webPreferences: {
webviewTag: true, webviewTag: true,
@ -84,15 +83,15 @@ const CiderBase = {
} }
) )
win.webContents.session.webRequest.onBeforeSendHeaders(async (details, callback) => { win.webContents.session.webRequest.onBeforeSendHeaders(async (details, callback) => {
if(details.url == "https://buy.itunes.apple.com/account/web/info"){ if (details.url === "https://buy.itunes.apple.com/account/web/info") {
details.requestHeaders['sec-fetch-site'] = 'same-site'; details.requestHeaders['sec-fetch-site'] = 'same-site';
details.requestHeaders['DNT'] = '1'; details.requestHeaders['DNT'] = '1';
let itspod = await win.webContents.executeJavaScript(`window.localStorage.getItem("music.ampwebplay.itspod")`) let itspod = await win.webContents.executeJavaScript(`window.localStorage.getItem("music.ampwebplay.itspod")`)
if (itspod != null) if (itspod != null)
details.requestHeaders['Cookie'] = `itspod=${itspod}` details.requestHeaders['Cookie'] = `itspod=${itspod}`
} }
callback({ requestHeaders: details.requestHeaders }) callback({requestHeaders: details.requestHeaders})
}) })
let location = `http://localhost:${CiderBase.clientPort}/` let location = `http://localhost:${CiderBase.clientPort}/`
@ -124,7 +123,7 @@ const CiderBase = {
ipcMain.handle('getYTLyrics', async (event, track, artist) => { ipcMain.handle('getYTLyrics', async (event, track, artist) => {
var u = track + " " + artist + " official video"; var u = track + " " + artist + " official video";
const videos = await yt.search(u); const videos = await yt.search(u);
return videos return videos
}) })
@ -187,9 +186,10 @@ const CiderBase = {
// Set window Handler // Set window Handler
win.webContents.setWindowOpenHandler(({url}) => { win.webContents.setWindowOpenHandler(({url}) => {
if (url.includes("apple") || url.includes("localhost")) { if (url.includes("apple") || url.includes("localhost")) {
return { action: "allow"} return {action: "allow"}
} }
shell.openExternal(url).catch(() => {}) shell.openExternal(url).catch(() => {
})
return { return {
action: 'deny' action: 'deny'
} }
@ -202,13 +202,17 @@ const CiderBase = {
win.webContents.setZoomFactor(screen.getPrimaryDisplay().scaleFactor) win.webContents.setZoomFactor(screen.getPrimaryDisplay().scaleFactor)
mpris.connect(win)
// Discord // Discord
discord.connect('911790844204437504'); discord.connect('911790844204437504');
ipcMain.on('playbackStateDidChange', (_event, a) => { ipcMain.on('playbackStateDidChange', (_event, a) => {
discord.updateActivity(a) discord.updateActivity(a)
mpris.updateState(a)
}); });
ipcMain.on('nowPlayingItemDidChange', (_event, a) => { ipcMain.on('nowPlayingItemDidChange', (_event, a) => {
discord.updateActivity(a) discord.updateActivity(a)
mpris.updateAttributes(a)
}); });
return win return win

View file

@ -2,16 +2,21 @@ const {app} = require('electron'),
DiscordRPC = require('discord-rpc') DiscordRPC = require('discord-rpc')
module.exports = { module.exports = {
/**
* Connects to Discord RPC
* @param {string} clientId
*/
connect: function (clientId) { connect: function (clientId) {
app.discord = {isConnected: false}; app.discord = {isConnected: false};
if (!app.cfg.get('general.discord_rpc')) return; if (!app.cfg.get('general.discord_rpc')) return;
DiscordRPC.register(clientId) // Apparently needed for ask to join, join, spectate etc. DiscordRPC.register(clientId) // Apparently needed for ask to join, join, spectate etc.
const client = new DiscordRPC.Client({ transport: "ipc" }); const client = new DiscordRPC.Client({transport: "ipc"});
app.discord = Object.assign(client,{error: false, activityCache: null, isConnected: false}); app.discord = Object.assign(client, {error: false, activityCache: null, isConnected: false});
// Login to Discord // Login to Discord
app.discord.login({ clientId }) app.discord.login({clientId})
.then(() => { .then(() => {
app.discord.isConnected = true; app.discord.isConnected = true;
}) })
@ -34,6 +39,9 @@ module.exports = {
}); });
}, },
/**
* Disconnects from Discord RPC
*/
disconnect: function () { disconnect: function () {
if (!app.cfg.get('general.discord_rpc') || !app.discord.isConnected) return; if (!app.cfg.get('general.discord_rpc') || !app.discord.isConnected) return;
@ -47,6 +55,10 @@ module.exports = {
} }
}, },
/**
* Sets the activity of the client
* @param {object} attributes
*/
updateActivity: function (attributes) { updateActivity: function (attributes) {
if (!app.cfg.get('general.discord_rpc')) return; if (!app.cfg.get('general.discord_rpc')) return;
@ -65,16 +77,18 @@ module.exports = {
state: `by ${attributes.artistName}`, state: `by ${attributes.artistName}`,
startTimestamp: attributes.startTime, startTimestamp: attributes.startTime,
endTimestamp: attributes.endTime, endTimestamp: attributes.endTime,
largeImageKey: (attributes.artwork.url.replace('{w}', '512').replace('{h}', '512') ) ?? 'cider', largeImageKey: (attributes.artwork.url.replace('{w}', '512').replace('{h}', '512')) ?? 'cider',
largeImageText: attributes.albumName, largeImageText: attributes.albumName,
smallImageKey: (attributes.status ? 'play' : 'pause'), smallImageKey: (attributes.status ? 'play' : 'pause'),
smallImageText: (attributes.status ? 'Playing': 'Paused'), smallImageText: (attributes.status ? 'Playing' : 'Paused'),
instance: true, instance: true,
buttons: [ buttons: [
{label: "Listen on Cider", url: listenURL}, {label: "Listen on Cider", url: listenURL},
] ]
}; };
if (ActivityObject.largeImageKey == "" || ActivityObject.largeImageKey == null) {ActivityObject.largeImageKey = "cider"} if (ActivityObject.largeImageKey == "" || ActivityObject.largeImageKey == null) {
ActivityObject.largeImageKey = "cider"
}
//console.log(`[LinkHandler] Listening URL has been set to: ${listenURL}`); //console.log(`[LinkHandler] Listening URL has been set to: ${listenURL}`);
// if (app.cfg.get('general.discordClearActivityOnPause')) { // if (app.cfg.get('general.discordClearActivityOnPause')) {
@ -104,16 +118,16 @@ module.exports = {
// ActivityObject = null // ActivityObject = null
// } else // } else
// { // {
delete ActivityObject.startTimestamp delete ActivityObject.startTimestamp
delete ActivityObject.endTimestamp delete ActivityObject.endTimestamp
ActivityObject.smallImageKey = 'pause' ActivityObject.smallImageKey = 'pause'
ActivityObject.smallImageText = 'Paused' ActivityObject.smallImageText = 'Paused'
//} //}
} }
if (ActivityObject) { if (ActivityObject) {
try { try {
// console.log(`[DiscordRPC][setActivity] Setting activity to ${JSON.stringify(ActivityObject)}`); // console.log(`[DiscordRPC][setActivity] Setting activity to ${JSON.stringify(ActivityObject)}`);
app.discord.setActivity(ActivityObject) app.discord.setActivity(ActivityObject)
} catch (err) { } catch (err) {
console.error(`[DiscordRPC][setActivity] ${err}`) console.error(`[DiscordRPC][setActivity] ${err}`)

View file

@ -1,5 +0,0 @@
const {app} = require('electron');
module.export = () => {
if (process.platform === "linux") app.commandLine.appendSwitch('disable-features', 'MediaSessionService');
}

View file

@ -1,16 +1,16 @@
const {app} = require('electron'), let mediaPlayer = null;
Player = require('mpris-service');
// Remember to use playerctl when debugging this.
// I'm just putting this here as I keep forgetting the command.
// Copied from AME
let mediaPlayer;
module.exports = { module.exports = {
/**
* Connects to the MPRIS interface.
* @param {Object} win - The BrowserWindow.
*/
connect: (win) => { connect: (win) => {
if (process.platform !== "linux") return; if (process.platform !== "linux") return;
const Player = require('mpris-service');
mediaPlayer = Player({ mediaPlayer = Player({
name: 'Cider', name: 'Cider',
identity: 'Cider', identity: 'Cider',
@ -24,7 +24,7 @@ module.exports = {
let pos_atr = {durationInMillis: 0}; let pos_atr = {durationInMillis: 0};
mediaPlayer.getPosition = function () { mediaPlayer.getPosition = function () {
const durationInMicro = pos_atr.durationInMillis * 1000; const durationInMicro = pos_atr.durationInMillis * 1000;
const percentage = parseFloat(0) || 0; const percentage = parseFloat("0") || 0;
return durationInMicro * percentage; return durationInMicro * percentage;
} }
@ -51,6 +51,10 @@ module.exports = {
}); });
}, },
/**
* Updates the MPRIS interface.
* @param {Object} attributes - The attributes of the track.
*/
updateAttributes: (attributes) => { updateAttributes: (attributes) => {
if (process.platform !== "linux") return; if (process.platform !== "linux") return;
@ -71,6 +75,10 @@ module.exports = {
mediaPlayer.metadata = MetaData mediaPlayer.metadata = MetaData
}, },
/**
* Updates the playback state of the MPRIS interface.
* @param {Object} attributes - The attributes of the track.
*/
updateState: (attributes) => { updateState: (attributes) => {
if (process.platform !== "linux") return; if (process.platform !== "linux") return;
@ -94,6 +102,9 @@ module.exports = {
} }
}, },
/**
* Closes the MPRIS interface.
*/
clearActivity: () => { clearActivity: () => {
if (process.platform !== "linux") return; if (process.platform !== "linux") return;
mediaPlayer.metadata = {'mpris:trackid': '/org/mpris/MediaPlayer2/TrackList/NoTrack'} mediaPlayer.metadata = {'mpris:trackid': '/org/mpris/MediaPlayer2/TrackList/NoTrack'}