Merge branch 'develop'
This commit is contained in:
commit
ea3d67b8b4
10 changed files with 197 additions and 1032 deletions
|
@ -7,4 +7,13 @@ Some notes about Cider's i18n support.
|
||||||
- The default language is used for messages that are not translated.
|
- The default language is used for messages that are not translated.
|
||||||
- Try when possible to keep the messages the similar in length to the English ones.
|
- Try when possible to keep the messages the similar in length to the English ones.
|
||||||
- Most of the strings in the content area are provided and translated by Apple themselves, and do not need to be translated.
|
- Most of the strings in the content area are provided and translated by Apple themselves, and do not need to be translated.
|
||||||
- The language Apple Music uses are dependent on the storefront region.
|
- The language Apple Music uses are dependent on the storefront region.
|
||||||
|
|
||||||
|
|
||||||
|
## Localization Notices
|
||||||
|
|
||||||
|
Several changes have been made to configuration options and will be listed below with the relevant locales that have
|
||||||
|
been modified, the ones not mentioned in the list need modifying.
|
||||||
|
|
||||||
|
* `settings.option.experimental.closeButtonBehaviour`: Changed to `close_button_hide` - Should be "Close Button Should Hide the Application". `.quit`, `.minimizeTaskbar` and `.minimizeTray` have been removed. Translations done for en_US.
|
||||||
|
* `term.loadingPlaylist`: Added for `en_US` and `en_PISS`.
|
|
@ -274,10 +274,7 @@
|
||||||
"settings.header.experimental": "Experimental",
|
"settings.header.experimental": "Experimental",
|
||||||
"settings.header.experimental.description": "Adjust the experimental settings for Cider.",
|
"settings.header.experimental.description": "Adjust the experimental settings for Cider.",
|
||||||
"settings.option.experimental.compactUI": "Compact UI", // Toggle
|
"settings.option.experimental.compactUI": "Compact UI", // Toggle
|
||||||
"settings.option.experimental.closeButtonBehaviour": "Close Button Behavior",
|
"settings.option.experimental.close_button_hide": "Close Button Should Hide the Application",
|
||||||
"settings.option.experimental.closeButtonBehaviour.quit": "Quit Cider",
|
|
||||||
"settings.option.experimental.closeButtonBehaviour.minimizeTaskbar": "Minimize to Taskbar",
|
|
||||||
"settings.option.experimental.closeButtonBehaviour.minimizeTray": "Minimize to Tray",
|
|
||||||
// Refer to term.disabled & term.enabled
|
// Refer to term.disabled & term.enabled
|
||||||
|
|
||||||
// Spatialization Menu
|
// Spatialization Menu
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as electron from 'electron';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export class AppEvents {
|
export class AppEvents {
|
||||||
private static protocols: any = [
|
private protocols: string[] = [
|
||||||
"ame",
|
"ame",
|
||||||
"cider",
|
"cider",
|
||||||
"itms",
|
"itms",
|
||||||
|
@ -10,20 +10,22 @@ export class AppEvents {
|
||||||
"musics",
|
"musics",
|
||||||
"music"
|
"music"
|
||||||
]
|
]
|
||||||
private static plugin: any = null;
|
private plugin: any = undefined;
|
||||||
private static store: any = null;
|
private store: any = undefined;
|
||||||
private static win: any = null;
|
private win: any = undefined;
|
||||||
|
private tray: any = undefined;
|
||||||
|
private i18n: any = undefined;
|
||||||
|
|
||||||
constructor(store: any) {
|
constructor(store: any) {
|
||||||
AppEvents.store = store
|
this.store = store
|
||||||
AppEvents.start(store);
|
this.start(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all actions that occur for the app on start (Mainly commandline arguments)
|
* Handles all actions that occur for the app on start (Mainly commandline arguments)
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
private static start(store: any): void {
|
private start(store: any): void {
|
||||||
console.info('[AppEvents] App started');
|
console.info('[AppEvents] App started');
|
||||||
|
|
||||||
/**********************************************************************************************************************
|
/**********************************************************************************************************************
|
||||||
|
@ -46,10 +48,10 @@ export class AppEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose GC
|
// Expose GC
|
||||||
electron.app.commandLine.appendSwitch('js-flags','--expose_gc')
|
electron.app.commandLine.appendSwitch('js-flags', '--expose_gc')
|
||||||
|
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
electron.app.setAppUserModelId("Cider") // For notification name
|
electron.app.setAppUserModelId(electron.app.getName()) // For notification name
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************
|
/***********************************************************************************************************************
|
||||||
|
@ -103,33 +105,39 @@ export class AppEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
public quit() {
|
public quit() {
|
||||||
console.log('App stopped');
|
console.log('[AppEvents] App quit');
|
||||||
}
|
}
|
||||||
|
|
||||||
public ready(plug: any) {
|
public ready(plug: any) {
|
||||||
AppEvents.plugin = plug
|
this.plugin = plug
|
||||||
console.log('[AppEvents] App ready');
|
console.log('[AppEvents] App ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
public bwCreated(win: Electron.BrowserWindow) {
|
public bwCreated(win: Electron.BrowserWindow, i18n: any) {
|
||||||
AppEvents.win = win
|
this.win = win
|
||||||
|
this.i18n = i18n
|
||||||
|
|
||||||
electron.app.on('open-url', (event, url) => {
|
electron.app.on('open-url', (event, url) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if (AppEvents.protocols.some((protocol: string) => url.includes(protocol))) {
|
if (this.protocols.some((protocol: string) => url.includes(protocol))) {
|
||||||
AppEvents.LinkHandler(url)
|
this.LinkHandler(url)
|
||||||
console.log(url)
|
console.log(url)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
AppEvents.InstanceHandler()
|
this.InstanceHandler()
|
||||||
|
this.InitTray()
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************
|
/***********************************************************************************************************************
|
||||||
* Private methods
|
* Private methods
|
||||||
**********************************************************************************************************************/
|
**********************************************************************************************************************/
|
||||||
|
|
||||||
private static LinkHandler(arg: string) {
|
/**
|
||||||
|
* Handles links (URI) and protocols for the application
|
||||||
|
* @param arg
|
||||||
|
*/
|
||||||
|
private LinkHandler(arg: string) {
|
||||||
if (!arg) return;
|
if (!arg) return;
|
||||||
|
|
||||||
// LastFM Auth URL
|
// LastFM Auth URL
|
||||||
|
@ -137,10 +145,10 @@ export class AppEvents {
|
||||||
let authURI = arg.split('/auth/')[1]
|
let authURI = arg.split('/auth/')[1]
|
||||||
if (authURI.startsWith('lastfm')) { // If we wanted more auth options
|
if (authURI.startsWith('lastfm')) { // If we wanted more auth options
|
||||||
const authKey = authURI.split('lastfm?token=')[1];
|
const authKey = authURI.split('lastfm?token=')[1];
|
||||||
AppEvents.store.set('lastfm.enabled', true);
|
this.store.set('lastfm.enabled', true);
|
||||||
AppEvents.store.set('lastfm.auth_token', authKey);
|
this.store.set('lastfm.auth_token', authKey);
|
||||||
AppEvents.win.webContents.send('LastfmAuthenticated', authKey);
|
this.win.webContents.send('LastfmAuthenticated', authKey);
|
||||||
AppEvents.plugin.callPlugin('lastfm', 'authenticate', authKey);
|
this.plugin.callPlugin('lastfm', 'authenticate', authKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Play
|
// Play
|
||||||
|
@ -156,7 +164,7 @@ export class AppEvents {
|
||||||
for (const [key, value] of Object.entries(mediaType)) {
|
for (const [key, value] of Object.entries(mediaType)) {
|
||||||
if (playParam.includes(key)) {
|
if (playParam.includes(key)) {
|
||||||
const id = playParam.split(key)[1]
|
const id = playParam.split(key)[1]
|
||||||
AppEvents.win.webContents.send('play', value, id)
|
this.win.webContents.send('play', value, id)
|
||||||
console.debug(`[LinkHandler] Attempting to load ${value} by id: ${id}`)
|
console.debug(`[LinkHandler] Attempting to load ${value} by id: ${id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,11 +173,14 @@ export class AppEvents {
|
||||||
console.log(arg)
|
console.log(arg)
|
||||||
let url = arg.split('//')[1]
|
let url = arg.split('//')[1]
|
||||||
console.warn(`[LinkHandler] Attempting to load url: ${url}`);
|
console.warn(`[LinkHandler] Attempting to load url: ${url}`);
|
||||||
AppEvents.win.webContents.send('play', 'url', url)
|
this.win.webContents.send('play', 'url', url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InstanceHandler() {
|
/**
|
||||||
|
* Handles the creation of a new instance of the app
|
||||||
|
*/
|
||||||
|
private InstanceHandler() {
|
||||||
|
|
||||||
// Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found)
|
// Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found)
|
||||||
const gotTheLock = electron.app.requestSingleInstanceLock()
|
const gotTheLock = electron.app.requestSingleInstanceLock()
|
||||||
|
@ -185,17 +196,97 @@ export class AppEvents {
|
||||||
console.log(arg)
|
console.log(arg)
|
||||||
if (arg.includes("cider://")) {
|
if (arg.includes("cider://")) {
|
||||||
console.debug('[InstanceHandler] (second-instance) Link detected with ' + arg)
|
console.debug('[InstanceHandler] (second-instance) Link detected with ' + arg)
|
||||||
AppEvents.LinkHandler(arg)
|
this.LinkHandler(arg)
|
||||||
} else if (arg.includes("--force-quit")) {
|
} else if (arg.includes("--force-quit")) {
|
||||||
console.warn('[InstanceHandler] (second-instance) Force Quit found. Quitting App.');
|
console.warn('[InstanceHandler] (second-instance) Force Quit found. Quitting App.');
|
||||||
electron.app.quit()
|
electron.app.quit()
|
||||||
} else if (AppEvents.win) {
|
} else if (this.win) {
|
||||||
if (AppEvents.win.isMinimized()) AppEvents.win.restore()
|
if (this.win.isMinimized()) this.win.restore()
|
||||||
AppEvents.win.focus()
|
this.win.focus()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the applications tray
|
||||||
|
*/
|
||||||
|
private InitTray() {
|
||||||
|
const icons = {
|
||||||
|
"win32": electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.ico`)).resize({
|
||||||
|
width: 32,
|
||||||
|
height: 32
|
||||||
|
}),
|
||||||
|
"linux": electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.png`)).resize({
|
||||||
|
width: 32,
|
||||||
|
height: 32
|
||||||
|
}),
|
||||||
|
"darwin": electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.png`)).resize({
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
console.log(this.i18n)
|
||||||
|
|
||||||
|
this.tray = new electron.Tray(process.platform === 'win32' ? icons.win32 : (process.platform === 'darwin' ? icons.darwin : icons.linux))
|
||||||
|
this.tray.setToolTip(electron.app.getName())
|
||||||
|
this.setTray(false)
|
||||||
|
|
||||||
|
this.tray.on('double-click', () => {
|
||||||
|
if (this.win) {
|
||||||
|
if (this.win.isVisible()) {
|
||||||
|
this.win.focus()
|
||||||
|
} else {
|
||||||
|
this.win.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.win.on('show', () => {
|
||||||
|
this.setTray(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.win.on('restore', () => {
|
||||||
|
this.setTray(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.win.on('hide', () => {
|
||||||
|
this.setTray(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.win.on('minimize', () => {
|
||||||
|
this.setTray(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tray context menu to a given state
|
||||||
|
* @param visible - BrowserWindow Visibility
|
||||||
|
*/
|
||||||
|
private setTray(visible: boolean = this.win.isVisible()) {
|
||||||
|
|
||||||
|
const menu = electron.Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: (visible ? this.i18n['action.tray.minimize'] : `${this.i18n['action.tray.show']} ${electron.app.getName()}`),
|
||||||
|
click: () => {
|
||||||
|
if (this.win) {
|
||||||
|
if (visible) {
|
||||||
|
this.win.hide()
|
||||||
|
} else {
|
||||||
|
this.win.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n['action.tray.quit'],
|
||||||
|
click: () => {
|
||||||
|
electron.app.quit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
this.tray.setContextMenu(menu)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export class ConfigStore {
|
||||||
|
|
||||||
private defaults: any = {
|
private defaults: any = {
|
||||||
"general": {
|
"general": {
|
||||||
"close_behavior": 0, // 0 = close, 1 = minimize, 2 = minimize to tray
|
"close_button_hide": true,
|
||||||
"open_on_startup": false,
|
"open_on_startup": false,
|
||||||
"discord_rpc": 1, // 0 = disabled, 1 = enabled as Cider, 2 = enabled as Apple Music
|
"discord_rpc": 1, // 0 = disabled, 1 = enabled as Cider, 2 = enabled as Apple Music
|
||||||
"discord_rpc_clear_on_pause": true,
|
"discord_rpc_clear_on_pause": true,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import * as express from "express";
|
||||||
import * as getPort from "get-port";
|
import * as getPort from "get-port";
|
||||||
import * as yt from "youtube-search-without-api-key";
|
import * as yt from "youtube-search-without-api-key";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Stream } from "stream";
|
import {Stream} from "stream";
|
||||||
import * as qrcode from "qrcode-terminal";
|
import * as qrcode from "qrcode-terminal";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import * as mm from 'music-metadata';
|
import * as mm from 'music-metadata';
|
||||||
|
@ -19,6 +19,7 @@ export class Win {
|
||||||
private app: any | undefined = null;
|
private app: any | undefined = null;
|
||||||
private store: any | undefined = null;
|
private store: any | undefined = null;
|
||||||
private devMode: boolean = !electron.app.isPackaged;
|
private devMode: boolean = !electron.app.isPackaged;
|
||||||
|
public i18n: any = {};
|
||||||
|
|
||||||
constructor(app: electron.App, store: any) {
|
constructor(app: electron.App, store: any) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
@ -76,7 +77,7 @@ export class Win {
|
||||||
* Creates the browser window
|
* Creates the browser window
|
||||||
*/
|
*/
|
||||||
async createWindow(): Promise<Electron.BrowserWindow> {
|
async createWindow(): Promise<Electron.BrowserWindow> {
|
||||||
this.clientPort = await getPort({ port: 9000 });
|
this.clientPort = await getPort({port: 9000});
|
||||||
this.verifyFiles();
|
this.verifyFiles();
|
||||||
|
|
||||||
// Load the previous state with fallback to defaults
|
// Load the previous state with fallback to defaults
|
||||||
|
@ -262,7 +263,7 @@ export class Win {
|
||||||
if (itspod != null)
|
if (itspod != null)
|
||||||
details.requestHeaders["Cookie"] = `itspod=${itspod}`;
|
details.requestHeaders["Cookie"] = `itspod=${itspod}`;
|
||||||
}
|
}
|
||||||
callback({ requestHeaders: details.requestHeaders });
|
callback({requestHeaders: details.requestHeaders});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -288,18 +289,29 @@ export class Win {
|
||||||
event.returnValue = process.platform;
|
event.returnValue = process.platform;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let i18nBase = fs.readFileSync(path.join(__dirname, "../../src/i18n/en_US.jsonc"), "utf8");
|
||||||
|
i18nBase = jsonc.parse(i18nBase)
|
||||||
|
try {
|
||||||
|
let i18n = fs.readFileSync(path.join(__dirname, `../../src/i18n/${this.store.general.language}.jsonc`), "utf8");
|
||||||
|
i18n = jsonc.parse(i18n)
|
||||||
|
this.i18n = Object.assign(i18nBase, i18n)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
electron.ipcMain.on("get-i18n", (event, key) => {
|
electron.ipcMain.on("get-i18n", (event, key) => {
|
||||||
let i18nBase = fs.readFileSync(path.join(__dirname, "../../src/i18n/en_US.jsonc"), "utf8");
|
let i18nBase = fs.readFileSync(path.join(__dirname, "../../src/i18n/en_US.jsonc"), "utf8");
|
||||||
i18nBase = jsonc.parse(i18nBase)
|
i18nBase = jsonc.parse(i18nBase)
|
||||||
try {
|
try {
|
||||||
let i18n = fs.readFileSync(path.join(__dirname, `../../src/i18n/${key}.jsonc`), "utf8");
|
let i18n = fs.readFileSync(path.join(__dirname, `../../src/i18n/${key}.jsonc`), "utf8");
|
||||||
i18n = jsonc.parse(i18n)
|
i18n = jsonc.parse(i18n)
|
||||||
Object.assign(i18nBase, i18n)
|
this.i18n = Object.assign(i18nBase, i18n)
|
||||||
}catch(e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
event.returnValue = e;
|
event.returnValue = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.i18n = i18nBase;
|
||||||
event.returnValue = i18nBase;
|
event.returnValue = i18nBase;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -330,11 +342,6 @@ export class Win {
|
||||||
event.returnValue = this.devMode;
|
event.returnValue = this.devMode;
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("close", () => {
|
|
||||||
// listen for close event
|
|
||||||
this.win.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
electron.ipcMain.on("put-library-songs", (event, arg) => {
|
electron.ipcMain.on("put-library-songs", (event, arg) => {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(this.paths.ciderCache, "library-songs.json"),
|
path.join(this.paths.ciderCache, "library-songs.json"),
|
||||||
|
@ -415,8 +422,8 @@ export class Win {
|
||||||
return await yt.search(u);
|
return await yt.search(u);
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.handle("setVibrancy", (event, key, value) => {
|
electron.ipcMain.on("close", () => {
|
||||||
this.win.setVibrancy(value);
|
this.win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("maximize", () => {
|
electron.ipcMain.on("maximize", () => {
|
||||||
|
@ -429,7 +436,7 @@ export class Win {
|
||||||
});
|
});
|
||||||
electron.ipcMain.on("unmaximize", () => {
|
electron.ipcMain.on("unmaximize", () => {
|
||||||
// listen for maximize event
|
// listen for maximize event
|
||||||
this.win.unmaximize();
|
this.win.unmaximize();
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("minimize", () => {
|
electron.ipcMain.on("minimize", () => {
|
||||||
|
@ -443,7 +450,7 @@ export class Win {
|
||||||
});
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("windowmin", (event, width, height) => {
|
electron.ipcMain.on("windowmin", (event, width, height) => {
|
||||||
this.win.setMinimumSize(width,height);
|
this.win.setMinimumSize(width, height);
|
||||||
})
|
})
|
||||||
|
|
||||||
electron.ipcMain.on("windowontop", (event, ontop) => {
|
electron.ipcMain.on("windowontop", (event, ontop) => {
|
||||||
|
@ -462,7 +469,7 @@ export class Win {
|
||||||
})
|
})
|
||||||
//Fullscreen
|
//Fullscreen
|
||||||
electron.ipcMain.on('detachDT', (event, _) => {
|
electron.ipcMain.on('detachDT', (event, _) => {
|
||||||
this.win.webContents.openDevTools({ mode: 'detach' });
|
this.win.webContents.openDevTools({mode: 'detach'});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -497,7 +504,7 @@ export class Win {
|
||||||
}
|
}
|
||||||
|
|
||||||
//QR Code
|
//QR Code
|
||||||
electron.ipcMain.handle('showQR', async (event , _) => {
|
electron.ipcMain.handle('showQR', async (event, _) => {
|
||||||
let url = `http://${getIp()}:${this.remotePort}`;
|
let url = `http://${getIp()}:${this.remotePort}`;
|
||||||
electron.shell.openExternal(`https://cider.sh/pair-remote?url=${btoa(encodeURI(url))}`);
|
electron.shell.openExternal(`https://cider.sh/pair-remote?url=${btoa(encodeURI(url))}`);
|
||||||
/*
|
/*
|
||||||
|
@ -510,11 +517,11 @@ export class Win {
|
||||||
'get url'
|
'get url'
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then(res => res.buffer())
|
.then(res => res.buffer())
|
||||||
.then(async(buffer) => {
|
.then(async (buffer) => {
|
||||||
try {
|
try {
|
||||||
const metadata = await mm.parseBuffer(buffer, 'audio/x-m4a');
|
const metadata = await mm.parseBuffer(buffer, 'audio/x-m4a');
|
||||||
let SoundCheckTag = metadata.native.iTunes[1].value
|
let SoundCheckTag = metadata.native.iTunes[1].value
|
||||||
console.log('sc',SoundCheckTag)
|
console.log('sc', SoundCheckTag)
|
||||||
this.win.webContents.send('SoundCheckTag', SoundCheckTag)
|
this.win.webContents.send('SoundCheckTag', SoundCheckTag)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
|
@ -564,6 +571,25 @@ export class Win {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isQuiting = false
|
||||||
|
|
||||||
|
this.win.on("close", (event: Event) => {
|
||||||
|
if ((this.store.general.close_button_hide || process.platform === "darwin" )&& !isQuiting) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.win.hide();
|
||||||
|
} else {
|
||||||
|
this.win.destroy();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
electron.app.on('before-quit', () => {
|
||||||
|
isQuiting = true
|
||||||
|
});
|
||||||
|
|
||||||
|
electron.app.on('window-all-closed', () => {
|
||||||
|
electron.app.quit()
|
||||||
|
})
|
||||||
|
|
||||||
this.win.on("closed", () => {
|
this.win.on("closed", () => {
|
||||||
this.win = null;
|
this.win = null;
|
||||||
});
|
});
|
||||||
|
@ -571,19 +597,20 @@ export class Win {
|
||||||
// Set window Handler
|
// Set window Handler
|
||||||
this.win.webContents.setWindowOpenHandler((x: any) => {
|
this.win.webContents.setWindowOpenHandler((x: any) => {
|
||||||
if (x.url.includes("apple") || x.url.includes("localhost")) {
|
if (x.url.includes("apple") || x.url.includes("localhost")) {
|
||||||
return { action: "allow" };
|
return {action: "allow"};
|
||||||
}
|
}
|
||||||
electron.shell.openExternal(x.url).catch(console.error);
|
electron.shell.openExternal(x.url).catch(console.error);
|
||||||
return { action: "deny" };
|
return {action: "deny"};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async broadcastRemote() {
|
private async broadcastRemote() {
|
||||||
function getIp() {
|
function getIp() {
|
||||||
let ip :any = false;
|
let ip: any = false;
|
||||||
let alias = 0;
|
let alias = 0;
|
||||||
const ifaces: any = os.networkInterfaces() ;
|
const ifaces: any = os.networkInterfaces();
|
||||||
for (var dev in ifaces) {
|
for (var dev in ifaces) {
|
||||||
ifaces[dev].forEach( (details: any) => {
|
ifaces[dev].forEach((details: any) => {
|
||||||
if (details.family === 'IPv4') {
|
if (details.family === 'IPv4') {
|
||||||
if (!/(loopback|vmware|internal|hamachi|vboxnet|virtualbox)/gi.test(dev + (alias ? ':' + alias : ''))) {
|
if (!/(loopback|vmware|internal|hamachi|vboxnet|virtualbox)/gi.test(dev + (alias ? ':' + alias : ''))) {
|
||||||
if (details.address.substring(0, 8) === '192.168.' ||
|
if (details.address.substring(0, 8) === '192.168.' ||
|
||||||
|
@ -595,14 +622,15 @@ export class Win {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) ;
|
});
|
||||||
}
|
}
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
const myString = `http://${getIp()}:${this.remotePort}`;
|
const myString = `http://${getIp()}:${this.remotePort}`;
|
||||||
let mdns = require('mdns-js');
|
let mdns = require('mdns-js');
|
||||||
const encoded = new Buffer(myString).toString('base64');
|
const encoded = new Buffer(myString).toString('base64');
|
||||||
var x = mdns.tcp('cider-remote');
|
var x = mdns.tcp('cider-remote');
|
||||||
var txt_record = {
|
var txt_record = {
|
||||||
"Ver": "131077",
|
"Ver": "131077",
|
||||||
'DvSv': '3689',
|
'DvSv': '3689',
|
||||||
|
@ -613,7 +641,7 @@ export class Win {
|
||||||
"CtlN": "Cider",
|
"CtlN": "Cider",
|
||||||
"iV": "196623"
|
"iV": "196623"
|
||||||
}
|
}
|
||||||
let server2 = mdns.createAdvertisement(x, `${await getPort({port: 3839})}`, { name: encoded, txt: txt_record });
|
let server2 = mdns.createAdvertisement(x, `${await getPort({port: 3839})}`, {name: encoded, txt: txt_record});
|
||||||
server2.start();
|
server2.start();
|
||||||
console.log('remote broadcasted')
|
console.log('remote broadcasted')
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ electron.app.on('ready', () => {
|
||||||
|
|
||||||
electron.components.whenReady().then(async () => {
|
electron.components.whenReady().then(async () => {
|
||||||
win = await Cider.createWindow()
|
win = await Cider.createWindow()
|
||||||
App.bwCreated(win);
|
App.bwCreated(win, Cider.i18n);
|
||||||
/// please dont change this for plugins to get proper and fully initialized Win objects
|
/// please dont change this for plugins to get proper and fully initialized Win objects
|
||||||
plug.callPlugins('onReady', win);
|
plug.callPlugins('onReady', win);
|
||||||
win.on("ready-to-show", () => {
|
win.on("ready-to-show", () => {
|
||||||
|
|
|
@ -1,171 +0,0 @@
|
||||||
import * as electron from 'electron';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
|
|
||||||
export default class MinimizeToTray {
|
|
||||||
/**
|
|
||||||
* Private variables for interaction in plugins
|
|
||||||
*/
|
|
||||||
private _win: any;
|
|
||||||
private _app: any;
|
|
||||||
private _store: any;
|
|
||||||
private _tray: any;
|
|
||||||
private _forceQuit = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base Plugin Details (Eventually implemented into a GUI in settings)
|
|
||||||
*/
|
|
||||||
public name: string = 'Minimize to tray';
|
|
||||||
public description: string = 'Allow Cider to minimize to tray';
|
|
||||||
public version: string = '1.0.0';
|
|
||||||
public author: string = 'vapormusic';
|
|
||||||
|
|
||||||
constructor(app: any, store: any) {
|
|
||||||
this._app = app;
|
|
||||||
this._store = store;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SetContextMenu(visibility : any) {
|
|
||||||
let self = this
|
|
||||||
if (visibility) {
|
|
||||||
this._tray.setContextMenu(electron.Menu.buildFromTemplate([
|
|
||||||
// {
|
|
||||||
// label: 'Check for Updates',
|
|
||||||
// click: function () {
|
|
||||||
// app.ame.utils.checkForUpdates(true)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
label: 'Minimize to Tray',
|
|
||||||
click: function () {
|
|
||||||
if (typeof self._win.hide === 'function') {
|
|
||||||
self._win.hide();
|
|
||||||
self.SetContextMenu(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
click: function () {
|
|
||||||
self._forceQuit = true; self._app.quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]));
|
|
||||||
} else {
|
|
||||||
this._tray.setContextMenu(electron.Menu.buildFromTemplate([
|
|
||||||
// {
|
|
||||||
// label: 'Check for Updates',
|
|
||||||
// click: function () {
|
|
||||||
// this._app.ame.utils.checkForUpdates(true)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
label: `Show ${electron.app.getName()}`,
|
|
||||||
click: function () {
|
|
||||||
if (typeof self._win.show === 'function') {
|
|
||||||
self._win.show();
|
|
||||||
self.SetContextMenu(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
click: function () {
|
|
||||||
self._forceQuit = true; self._app.quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on app ready
|
|
||||||
*/
|
|
||||||
onReady(win: any): void {
|
|
||||||
this._win = win;
|
|
||||||
const winTray = electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.ico`)).resize({
|
|
||||||
width: 32,
|
|
||||||
height: 32
|
|
||||||
})
|
|
||||||
const macTray = electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.png`)).resize({
|
|
||||||
width: 20,
|
|
||||||
height: 20
|
|
||||||
})
|
|
||||||
const linuxTray = electron.nativeImage.createFromPath(path.join(__dirname, `../../resources/icons/icon.png`)).resize({
|
|
||||||
width: 32,
|
|
||||||
height: 32
|
|
||||||
})
|
|
||||||
let trayIcon : any ;
|
|
||||||
if (process.platform === "win32") {
|
|
||||||
trayIcon = winTray
|
|
||||||
} else if (process.platform === "linux") {
|
|
||||||
trayIcon = linuxTray
|
|
||||||
} else if (process.platform === "darwin") {
|
|
||||||
trayIcon = macTray
|
|
||||||
}
|
|
||||||
|
|
||||||
this._tray = new electron.Tray(trayIcon)
|
|
||||||
this._tray.setToolTip(this._app.getName());
|
|
||||||
this.SetContextMenu(true);
|
|
||||||
|
|
||||||
this._tray.on('double-click', () => {
|
|
||||||
if (typeof this._win.show === 'function') {
|
|
||||||
if (this._win.isVisible()) {
|
|
||||||
this._win.focus()
|
|
||||||
} else {
|
|
||||||
this._win.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
electron.ipcMain.handle("update-store-mtt", (event, value) => {
|
|
||||||
this._store.general["close_behavior"] = value;
|
|
||||||
})
|
|
||||||
electron.ipcMain.on("win-close", (event, value) => {
|
|
||||||
console.log("tray", this._store.general["close_behavior"] )
|
|
||||||
if (this._forceQuit || this._store.general["close_behavior"] == '0' ) {
|
|
||||||
this._app.quit();
|
|
||||||
} else if (this._store.general["close_behavior"] == '1') {
|
|
||||||
this._win.minimize();
|
|
||||||
} else {
|
|
||||||
this._win.hide();
|
|
||||||
this.SetContextMenu(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._win.on("close", (e :any) => {
|
|
||||||
if (this._forceQuit || this._store.general["close_behavior"] == '0' ) {
|
|
||||||
this._app.quit();
|
|
||||||
} else if (this._store.general["close_behavior"] == '1') {
|
|
||||||
e.preventDefault();
|
|
||||||
this._win.minimize();
|
|
||||||
} else {
|
|
||||||
e.preventDefault();
|
|
||||||
this._win.hide();
|
|
||||||
this.SetContextMenu(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on app stop
|
|
||||||
*/
|
|
||||||
onBeforeQuit(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on playback State Change
|
|
||||||
* @param attributes Music Attributes (attributes.state = current state)
|
|
||||||
*/
|
|
||||||
onPlaybackStateDidChange(attributes: object): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on song change
|
|
||||||
* @param attributes Music Attributes
|
|
||||||
*/
|
|
||||||
onNowPlayingItemDidChange(attributes: object): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3533,8 +3533,7 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeWindow(){
|
closeWindow(){
|
||||||
// window.close doesnt call the win "close" event for some reason
|
ipcRenderer.send('close');
|
||||||
ipcRenderer.send('win-close');
|
|
||||||
},
|
},
|
||||||
checkForUpdate(){
|
checkForUpdate(){
|
||||||
ipcRenderer.send('check-for-update')
|
ipcRenderer.send('check-for-update')
|
||||||
|
|
|
@ -1,778 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<link rel="preconnect" href="https://amp-api.music.apple.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://api.music.apple.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://is1-ssl.mzstatic.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://is2-ssl.mzstatic.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://is3-ssl.mzstatic.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://is4-ssl.mzstatic.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://is5-ssl.mzstatic.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://play.itunes.apple.com/" crossorigin/>
|
|
||||||
<link rel="preconnect" href="https://aod-ssl.itunes.apple.com/" crossorigin/>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
|
|
||||||
<title>Cider</title>
|
|
||||||
<link rel="stylesheet" href="style-old.css?v=2">
|
|
||||||
<script src="vue.js"></script>
|
|
||||||
<script src="sortable.min.js"></script>
|
|
||||||
<script src="vuedraggable.umd.min.js"></script>
|
|
||||||
<link rel="manifest" href="./manifest.json?v=2">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body oncontextmenu="return false;" loading="1">
|
|
||||||
<div id="app">
|
|
||||||
<div id="app-main">
|
|
||||||
<div class="app-chrome">
|
|
||||||
<div class="app-chrome--left">
|
|
||||||
<div class="app-chrome-item full-height">
|
|
||||||
<div class="app-title"></div>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
|
||||||
@click="mk.shuffleMode = 1"></button>
|
|
||||||
<button class="playback-button--small shuffle active" v-else @click="mk.shuffleMode = 0"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button previous" @click="mk.skipToPreviousItem()"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
|
||||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
|
||||||
@click="mk.repeatMode = 1"></button>
|
|
||||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
|
|
||||||
v-else-if="mk.repeatMode == 1"></button>
|
|
||||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
|
|
||||||
v-else-if="mk.repeatMode == 2"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome--center">
|
|
||||||
<div class="app-chrome-item playback-controls">
|
|
||||||
<template v-if="mkReady()">
|
|
||||||
<div class="app-playback-controls">
|
|
||||||
<div class="artwork" :style="{'--artwork': getNowPlayingArtwork(42)}"></div>
|
|
||||||
<div class="playback-info">
|
|
||||||
<div class="song-name">
|
|
||||||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
|
||||||
</div>
|
|
||||||
<div class="song-artist">
|
|
||||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }} — {{
|
|
||||||
mk.nowPlayingItem["attributes"]["albumName"] }}
|
|
||||||
</div>
|
|
||||||
<div class="song-progress">
|
|
||||||
<input type="range" step="0.01" min="0"
|
|
||||||
@change="mk.seekToTime($event.target.value)"
|
|
||||||
:max="mk.currentPlaybackDuration"
|
|
||||||
:value="playerLCD.playbackDuration">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="actions">❤️</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome--right">
|
|
||||||
<div class="app-chrome-item volume display--large">
|
|
||||||
<input type="range" class="" step="0.01" min="0" max="1" v-model="mk.volume"
|
|
||||||
v-if="typeof mk.volume != 'undefined'">
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item generic">
|
|
||||||
<button class="playback-button--small">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 22" version="1.1" fill="#fff"
|
|
||||||
style="width: 100%; height: 100%; fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 1.41421">
|
|
||||||
<path
|
|
||||||
d="M16.811,12.75c0.245,-0.355 0.389,-0.786 0.389,-1.25c0,-1.215 -0.985,-2.2 -2.2,-2.2c-1.215,0 -2.2,0.985 -2.2,2.2c0,0.466 0.145,0.898 0.392,1.254l-0.83,1.047c-0.537,-0.616 -0.862,-1.42 -0.862,-2.301c0,-1.933 1.567,-3.5 3.5,-3.5c1.933,0 3.5,1.567 3.5,3.5c0,0.879 -0.324,1.683 -0.859,2.297l-0.83,-1.047Zm1.271,1.604c0.694,-0.749 1.118,-1.752 1.118,-2.854c0,-2.32 -1.88,-4.2 -4.2,-4.2c-2.32,0 -4.2,1.88 -4.2,4.2c0,1.103 0.425,2.107 1.121,2.857l-0.814,1.028c-0.993,-0.995 -1.607,-2.368 -1.607,-3.885c0,-3.038 2.462,-5.5 5.5,-5.5c3.038,0 5.5,2.462 5.5,5.5c0,1.515 -0.613,2.887 -1.604,3.882l-0.814,-1.028Zm1.252,1.58c1.151,-1.126 1.866,-2.697 1.866,-4.434c0,-3.424 -2.776,-6.2 -6.2,-6.2c-3.424,0 -6.2,2.776 -6.2,6.2c0,1.739 0.716,3.311 1.869,4.437l-0.811,1.023c-1.452,-1.368 -2.358,-3.308 -2.358,-5.46c0,-4.142 3.358,-7.5 7.5,-7.5c4.142,0 7.5,3.358 7.5,7.5c0,2.15 -0.905,4.089 -2.355,5.457l-0.811,-1.023Zm-0.227,2.066l-8.219,0c-0.355,0 -0.515,-0.434 -0.27,-0.717l4.058,-5.12c0.178,-0.217 0.474,-0.217 0.652,0l4.058,5.12c0.237,0.283 0.085,0.717 -0.279,0.717Z"
|
|
||||||
style="fill-rule:nonzero"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item generic">
|
|
||||||
<button class="playback-button--small queue"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item generic">
|
|
||||||
<button class="playback-button--small lyrics"
|
|
||||||
@click="drawertest = !drawertest; lyricon =!lyricon; if(drawertest == true){loadLyrics();}"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item full-height">
|
|
||||||
<div class="window-controls">
|
|
||||||
<div class="minimize" @click="ipcRenderer.send('minimize')"></div>
|
|
||||||
<div class="minmax restore" v-if="chrome.maximized" @click="ipcRenderer.send('maximize')"></div>
|
|
||||||
<div class="minmax" v-else @click="ipcRenderer.send('maximize')"></div>
|
|
||||||
<div class="close" @click="ipcRenderer.send('close')"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="app-navigation">
|
|
||||||
<div id="app-sidebar">
|
|
||||||
<div class="app-sidebar-header">
|
|
||||||
<div class="search-input-container">
|
|
||||||
<div class="search-input--icon"></div>
|
|
||||||
<input type="search"
|
|
||||||
spellcheck="false"
|
|
||||||
@click="showSearch()"
|
|
||||||
@change="showSearch();searchQuery()"
|
|
||||||
placeholder="Search..."
|
|
||||||
v-model="search.term"
|
|
||||||
class="search-input">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="app-sidebar-content">
|
|
||||||
<div class="app-sidebar-header-text">
|
|
||||||
Apple Music
|
|
||||||
</div>
|
|
||||||
<sidebar-library-item name="Listen Now" page="listen_now"></sidebar-library-item>
|
|
||||||
<sidebar-library-item name="Browse" page="browse"></sidebar-library-item>
|
|
||||||
<sidebar-library-item name="Radio" page="radio"></sidebar-library-item>
|
|
||||||
<div class="app-sidebar-header-text">
|
|
||||||
Library
|
|
||||||
</div>
|
|
||||||
<sidebar-library-item name="Songs" page="library-songs"></sidebar-library-item>
|
|
||||||
<sidebar-library-item name="Albums" page="library-albums"></sidebar-library-item>
|
|
||||||
<sidebar-library-item name="Artists" page="library-artists"></sidebar-library-item>
|
|
||||||
<sidebar-library-item name="Made For You" page="library-madeforyou"></sidebar-library-item>
|
|
||||||
<div class="app-sidebar-header-text">
|
|
||||||
Playlists
|
|
||||||
</div>
|
|
||||||
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id" :href="item.href"
|
|
||||||
@click='app.page=`playlist_` + item.id ; showingPlaylist = [];getPlaylistFromID(app.page.substring(9))'>
|
|
||||||
{{ item.attributes.name }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<transition name="wpfade">
|
|
||||||
<div class="app-sidebar-content" v-if="chrome.menuOpened">
|
|
||||||
<button class="app-sidebar-item" @click="chrome.hideUserInfo = !chrome.hideUserInfo">
|
|
||||||
Toggle Personal Info
|
|
||||||
</button>
|
|
||||||
<button class="app-sidebar-item">
|
|
||||||
About
|
|
||||||
</button>
|
|
||||||
<button class="app-sidebar-item">
|
|
||||||
Discord
|
|
||||||
</button>
|
|
||||||
<button class="app-sidebar-item">
|
|
||||||
Settings
|
|
||||||
</button>
|
|
||||||
<button class="app-sidebar-item">
|
|
||||||
Sign Out
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
<div class="app-sidebar-footer">
|
|
||||||
<input type="range" class="display--small">
|
|
||||||
<button class="app-sidebar-button" style="width:100%"
|
|
||||||
@click="chrome.menuOpened = !chrome.menuOpened">
|
|
||||||
<template v-if="chrome.userinfo.attributes">
|
|
||||||
<img class="sidebar-user-icon" loading="lazy"
|
|
||||||
|
|
||||||
:src="getMediaItemArtwork(chrome.userinfo.attributes['artwork'] ? chrome.userinfo.attributes['artwork']['url'] : '', 26)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="sidebar-user-text" v-if="!chrome.hideUserInfo">
|
|
||||||
<template v-if="chrome.userinfo.attributes">
|
|
||||||
<div class="fullname text-overflow-elipsis">{{ chrome.userinfo.attributes.name }}</div>
|
|
||||||
<div class="handle-text text-overflow-elipsis">@{{ chrome.userinfo.attributes.handle
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
Sign in
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="sidebar-user-text" v-else>
|
|
||||||
Cider
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="app-sidebar-notification" v-if="library.songs.downloadState == 1">
|
|
||||||
<div>Updating your library...</div>
|
|
||||||
<div>{{ library.songs.meta.progress }} / {{ library.songs.meta.total }}</div>
|
|
||||||
<div style="width: 100%">
|
|
||||||
<progress style="width: 80%;" :value="library.songs.meta.progress"
|
|
||||||
:max="library.songs.meta.total"></progress>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="app-content">
|
|
||||||
<!-- Playlist / Album page-->
|
|
||||||
<transition name="wpfade">
|
|
||||||
<template v-if="page.includes('playlist_')">
|
|
||||||
<cider-playlist :data="showingPlaylist"></cider-playlist>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<transition name="wpfade">
|
|
||||||
<template v-if="page.includes('album_')">
|
|
||||||
<cider-playlist :data="showingPlaylist"></cider-playlist>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
</transition>
|
|
||||||
<!-- Browse -->
|
|
||||||
<transition name="wpfade">
|
|
||||||
<template v-if="page == 'browse'">
|
|
||||||
<div class="content-inner">
|
|
||||||
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start
|
|
||||||
MusicKit
|
|
||||||
</button>
|
|
||||||
<button id="apple-music-unauthorize" class="md-btn md-btn-primary" @click="unauthorize()">
|
|
||||||
Stop
|
|
||||||
MusicKit
|
|
||||||
</button>
|
|
||||||
<br>
|
|
||||||
<template v-if="mk.nowPlayingItem">
|
|
||||||
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
|
|
||||||
<br>
|
|
||||||
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
|
|
||||||
</template>
|
|
||||||
<div><input type="text" v-model="quickPlayQuery">
|
|
||||||
<button @click="quickPlay(quickPlayQuery)">Play</button>
|
|
||||||
</div>
|
|
||||||
<h1 class="header-text">Browse</h1>
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu tincidunt
|
|
||||||
consectetur, nisl nunc euismod nisi, eu porttitor nisl nisi euismod nisi.
|
|
||||||
</p>
|
|
||||||
<div class="media-item--small">
|
|
||||||
<div class="artwork">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="text">
|
|
||||||
Text
|
|
||||||
</div>
|
|
||||||
<div class="subtext">
|
|
||||||
Subtext
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<h1 class="header-text">Listen Now</h1>
|
|
||||||
<div class="winbox">
|
|
||||||
<div class="fancy">990kbps</div>
|
|
||||||
<div class="">
|
|
||||||
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
|
|
||||||
<button class="md-btn">Button</button>
|
|
||||||
<button class="md-btn md-btn-primary">Button</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<!-- Listen Now -->
|
|
||||||
<transition v-on:enter="getListenNow()" name="wpfade">
|
|
||||||
<template v-if="page == 'listen_now'" @created="console.log('listennow')">
|
|
||||||
<cider-listen-now :data="listennow"></cider-listen-now>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<!-- Radio -->
|
|
||||||
<transition v-on:enter="getRadioStations()" name="wpfade">
|
|
||||||
<template v-if="page == 'radio'" @created="console.log('radio')">
|
|
||||||
<div class="content-inner">
|
|
||||||
<h1 class="header-text">Radio</h1>
|
|
||||||
<h3>Recent Stations</h3>
|
|
||||||
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<!-- Search -->
|
|
||||||
<transition name="wpfade">
|
|
||||||
<template v-if="page == 'search'">
|
|
||||||
<cider-search :search="search"></cider-search>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<!-- Library - Songs -->
|
|
||||||
<transition name="wpfade" v-on:enter="getLibrarySongsFull()">
|
|
||||||
<template v-if="page == 'library-songs'">
|
|
||||||
<div class="content-inner">
|
|
||||||
<h1 class="header-text">Songs</h1>
|
|
||||||
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
|
|
||||||
<div class="search-input--icon"></div>
|
|
||||||
<input type="search"
|
|
||||||
style="width:100%;"
|
|
||||||
spellcheck="false"
|
|
||||||
placeholder="Search..."
|
|
||||||
@input="searchLibrarySongs"
|
|
||||||
v-model="library.songs.search"
|
|
||||||
class="search-input">
|
|
||||||
</div>
|
|
||||||
<mediaitem-list-item :item="item"
|
|
||||||
v-for="item in library.songs.displayListing"></mediaitem-list-item>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
<!-- Library - Albums -->
|
|
||||||
<transition name="wpfade" v-on:enter="getLibraryAlbums()">
|
|
||||||
<template v-if="page == 'library-albums'">
|
|
||||||
<div class="content-inner">
|
|
||||||
<h1 class="header-text">Albums</h1>
|
|
||||||
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
|
|
||||||
<div class="search-input--icon"></div>
|
|
||||||
<input type="search"
|
|
||||||
style="width:100%;"
|
|
||||||
spellcheck="false"
|
|
||||||
placeholder="Search..."
|
|
||||||
class="search-input">
|
|
||||||
</div>
|
|
||||||
<mediaitem-square-large :item="item"
|
|
||||||
v-for="item in library.albums.listing"></mediaitem-square-large>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
<transition name="drawertransition">
|
|
||||||
<div class="app-drawer" v-if="drawertest">
|
|
||||||
<lyrics-view v-if="drawertest && lyricon" :time="lyriccurrenttime" :lyrics="lyrics"></lyrics-view>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<transition name="wpfade">
|
|
||||||
<img v-show="chrome.artworkReady"
|
|
||||||
@load="chrome.artworkReady = true"
|
|
||||||
class="bg-artwork"
|
|
||||||
:src="getNowPlayingArtworkBG(32)">
|
|
||||||
</transition>
|
|
||||||
<transition name="wpfade">
|
|
||||||
<div class="bg-artwork--placeholder" v-else></div>
|
|
||||||
</transition>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/x-template" id="mediaitem-artwork">
|
|
||||||
<template v-if="type == 'artists'">
|
|
||||||
<div class="mediaitem-artwork rounded"
|
|
||||||
>
|
|
||||||
<img :src="app.getMediaItemArtwork(url, size)"
|
|
||||||
class="mediaitem-artwork--img">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="mediaitem-artwork"
|
|
||||||
>
|
|
||||||
<img :src="app.getMediaItemArtwork(url, size)"
|
|
||||||
class="mediaitem-artwork--img">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Generic Collection of MediaItems -->
|
|
||||||
<script type="text/x-template" id="collection-view-generic">
|
|
||||||
<template>
|
|
||||||
<div class="content-inner">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Listen Now -->
|
|
||||||
<script type="text/x-template" id="cider-listen-now">
|
|
||||||
<div class="content-inner">
|
|
||||||
<h1 class="header-text">Listen Now</h1>
|
|
||||||
<template v-for="recom in data.data">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : ""}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
|
||||||
<button class="cd-btn-seeall">See All</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template v-if="recom.attributes.display.kind == 'MusicCoverShelf'">
|
|
||||||
<mediaitem-scroller-horizontal-large
|
|
||||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="recom.attributes.display.kind == 'MusicSuperHeroShelf'">
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<mediaitem-scroller-horizontal-sp
|
|
||||||
:items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal-sp>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Album / Playlist View -->
|
|
||||||
<script type="text/x-template" id="cider-playlist">
|
|
||||||
<div class="content-inner">
|
|
||||||
<template v-if="data != [] && data.attributes != []">
|
|
||||||
<div class="playlist-display row">
|
|
||||||
<div class="col-auto">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : (data.relationships.tracks.data.length > 0 ? data.relationships.tracks.data[0].attributes.artwork.url ?? '':'')"
|
|
||||||
size="200"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="col playlist-info">
|
|
||||||
<div class="playlist-name">{{data.attributes.name ?? (data.attributes.title ?? '') ?? ''}}</div>
|
|
||||||
<div class="playlist-artist" v-if="data.attributes.artistName">{{data.attributes.artistName ??
|
|
||||||
''}}
|
|
||||||
</div>
|
|
||||||
<div class="playlist-desc"
|
|
||||||
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.short ?? (data.attributes.editorialNotes.standard ?? '') ) : (data.attributes.description ? (data.attributes.description.short ?? (data.attributes.description.standard ?? '')) : ''))"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<mediaitem-list-item :item="item"
|
|
||||||
v-for="item in data.relationships.tracks.data"></mediaitem-list-item>
|
|
||||||
<div class="playlist-time">{{app.getTotalTime()}}</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Search -->
|
|
||||||
<script type="text/x-template" id="cider-search">
|
|
||||||
<div class="content-inner">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
|
|
||||||
<template>
|
|
||||||
<h3>Top Result</h3>
|
|
||||||
<mediaitem-square-large :item="getTopResult()"></mediaitem-square>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="col" v-if="search.results.songs">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3>Songs</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto flex-center" v-if="search.results.songs.data.length >= 6">
|
|
||||||
<button class="cd-btn-seeall">See All</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mediaitem-list-item :item="item"
|
|
||||||
v-for="item in search.results.songs.data.limit(6)"></mediaitem-list-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-if="search.results['meta']">
|
|
||||||
<template v-if="search.results.albums">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3>Albums</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto flex-center" v-if="search.results.albums.data.length >= 10">
|
|
||||||
<button class="cd-btn-seeall">See All</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<mediaitem-scroller-horizontal-large
|
|
||||||
:items="search.results.albums.data.limit(10)"></mediaitem-scroller-horizontal-large>
|
|
||||||
</template>
|
|
||||||
<template v-if="search.results.artists">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3>Artists</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto flex-center" v-if="search.results.artists.data.length >= 5">
|
|
||||||
<button class="cd-btn-seeall">See All</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<mediaitem-square-large :item="item"
|
|
||||||
v-for="item in search.results.artists.data.limit(5)"></mediaitem-square-large>
|
|
||||||
</template>
|
|
||||||
<template v-if="search.results.playlists">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3>Playlists</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto flex-center" v-if="search.results.playlists.data.length >= 10">
|
|
||||||
<button class="cd-btn-seeall">See All</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<mediaitem-square-large :item="item"
|
|
||||||
v-for="item in search.results.playlists.data.limit(10)"></mediaitem-square-large>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-template" id="am-musiccovershelf">
|
|
||||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Sidebar Item -->
|
|
||||||
<script type="text/x-template" id="sidebar-library-item">
|
|
||||||
<button class="app-sidebar-item"
|
|
||||||
:class="$parent.getSidebarItemClass(page)"
|
|
||||||
@click="$parent.page = page">{{ name }}
|
|
||||||
</button>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Horizontal MediaItem Scroller -->
|
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal">
|
|
||||||
<template>
|
|
||||||
<div class="cd-hmedia-scroller">
|
|
||||||
<mediaitem-square :item="item"
|
|
||||||
v-for="item in items"></mediaitem-square>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Horizontal MediaItem Scroller (Large) -->
|
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
|
||||||
<template>
|
|
||||||
<div class="cd-hmedia-scroller">
|
|
||||||
<mediaitem-square-large :item="item"
|
|
||||||
v-for="item in items"></mediaitem-square-large>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Horizontal MediaItem Scroller (SP : Special) -->
|
|
||||||
|
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
|
||||||
<template>
|
|
||||||
<div class="cd-hmedia-scroller">
|
|
||||||
<mediaitem-square-sp :item="item"
|
|
||||||
v-for="item in items"></mediaitem-square-sp>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- MediaItem List Item -->
|
|
||||||
|
|
||||||
<script type="text/x-template" id="mediaitem-list-item">
|
|
||||||
<template>
|
|
||||||
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
|
|
||||||
class="cd-mediaitem-list-item">
|
|
||||||
<div class="artwork">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
|
||||||
size="34"
|
|
||||||
:type="item.type"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="info-rect">
|
|
||||||
<div class="title text-overflow-elipsis">
|
|
||||||
{{ item.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="subtitle text-overflow-elipsis">
|
|
||||||
<template v-if="item.attributes.artistName">
|
|
||||||
{{ item.attributes.artistName }}
|
|
||||||
<template v-if="item.attributes.albumName">
|
|
||||||
— {{ item.attributes.albumName }}
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="content-rating" v-if="item.attributes.contentRating">
|
|
||||||
{{ item.attributes.contentRating }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- MediaItem Horizontal Rectangle -->
|
|
||||||
<script type="text/x-template" id="mediaitem-hrect">
|
|
||||||
<template>
|
|
||||||
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
|
|
||||||
class="cd-mediaitem-hrect">
|
|
||||||
<div class="artwork">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
|
||||||
size="70"
|
|
||||||
:type="item.type"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="info-rect">
|
|
||||||
<div class="title text-overflow-elipsis">
|
|
||||||
{{ item.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="subtitle text-overflow-elipsis">
|
|
||||||
{{ item.type }}
|
|
||||||
<template v-if="item.attributes.artistName">
|
|
||||||
∙ {{ item.attributes.artistName }}
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- MediaItem Square -->
|
|
||||||
|
|
||||||
<script type="text/x-template" id="mediaitem-square">
|
|
||||||
<template>
|
|
||||||
<div @click="app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)"
|
|
||||||
class="cd-mediaitem-square">
|
|
||||||
<div class="artwork">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
|
||||||
size="300"
|
|
||||||
:type="item.type"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="title text-overflow-elipsis">
|
|
||||||
{{ item.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
|
|
||||||
{{ item.attributes.artistName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- MediaItem Square (Large) -->
|
|
||||||
|
|
||||||
<script type="text/x-template" id="mediaitem-square-large">
|
|
||||||
<template>
|
|
||||||
<div style="position: relative; display: inline-flex;">
|
|
||||||
<div @click.self='app.routeView(item)'
|
|
||||||
class="cd-mediaitem-square-large">
|
|
||||||
<div class="artwork">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
|
||||||
size="300"
|
|
||||||
:type="item.type"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
|
||||||
<div class="button" style="
|
|
||||||
border-radius: 50%;
|
|
||||||
background: rgba(50,50,50,0.7);"
|
|
||||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
|
|
||||||
width: '40px',
|
|
||||||
height: '40px',} :
|
|
||||||
{margin: '35px',
|
|
||||||
width: '120px',
|
|
||||||
height: '120px',}]"
|
|
||||||
@click="app.playMediaItem(item)">
|
|
||||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
|
||||||
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
|
|
||||||
{{ item.attributes.name ?? '' }}
|
|
||||||
</div>
|
|
||||||
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
|
|
||||||
{{ item.attributes.artistName ?? '' }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
|
||||||
<div class="button" style="
|
|
||||||
border-radius: 50%;
|
|
||||||
background: rgba(50,50,50,0.7);"
|
|
||||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
|
|
||||||
width: '40px',
|
|
||||||
height: '40px',} :
|
|
||||||
{margin: '35px',
|
|
||||||
width: '120px',
|
|
||||||
height: '120px',}]"
|
|
||||||
@click="app.playMediaItem(item)">
|
|
||||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
|
||||||
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- MediaItem Square SP -->
|
|
||||||
<script type="text/x-template" id="mediaitem-square-sp">
|
|
||||||
<template>
|
|
||||||
<div style="position: relative; display: inline-flex;">
|
|
||||||
<div @click.self='app.routeView(item)'
|
|
||||||
class="cd-mediaitem-square-sp"
|
|
||||||
:style="{'--spcolor' : (item.attributes.artwork.bgColor != null) ? ('#'+item.attributes.artwork.bgColor) : `black`}">
|
|
||||||
<div class="artwork">
|
|
||||||
<mediaitem-artwork
|
|
||||||
:url="item.attributes.artwork ? item.attributes.artwork.url : ''"
|
|
||||||
size="300"
|
|
||||||
:type="item.type"
|
|
||||||
></mediaitem-artwork>
|
|
||||||
</div>
|
|
||||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
|
||||||
<div class="button" style="
|
|
||||||
border-radius: 50%;
|
|
||||||
background: rgba(50,50,50,0.7);"
|
|
||||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
|
|
||||||
width: '40px',
|
|
||||||
height: '40px',} :
|
|
||||||
{margin: '35px',
|
|
||||||
width: '120px',
|
|
||||||
height: '120px',}]"
|
|
||||||
@click="app.playMediaItem(item)">
|
|
||||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
|
||||||
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="title text-overflow-elipsis"
|
|
||||||
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
|
|
||||||
style="font-weight: 600">
|
|
||||||
{{ item.attributes.name }}
|
|
||||||
</div>
|
|
||||||
<div class="subtitle text-overflow-elipsis"
|
|
||||||
:style="{'color' : (item.attributes.artwork.textColor1 != null) ? ('#'+item.attributes.artwork.textColor1) : `#eee`}"
|
|
||||||
style="padding-left: 4px;padding-right: 4px; display: -webkit-box;-webkit-box-orient: vertical; -webkit-line-clamp: 2;white-space: normal;">
|
|
||||||
{{ (item.attributes.editorialNotes != null) ? item.attributes.editorialNotes.short
|
|
||||||
:(item.attributes.artistName ?? '') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cd-mediaitem-square-large-overlay" @click.self='app.routeView(item)'>
|
|
||||||
<div class="button" style="
|
|
||||||
border-radius: 50%;
|
|
||||||
background: rgba(50,50,50,0.7);"
|
|
||||||
:style="[(!(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('radioStation') && !(item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')): (item.type ?? '')).includes('song')) ? {'margin': '140px',
|
|
||||||
width: '40px',
|
|
||||||
height: '40px',} :
|
|
||||||
{margin: '35px',
|
|
||||||
width: '120px',
|
|
||||||
height: '120px',}]"
|
|
||||||
@click="app.playMediaItem(item)">
|
|
||||||
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" class="glyph">
|
|
||||||
<path d="M11.3545232,18.4180929 L18.4676039,14.242665 C19.0452323,13.9290954 19.0122249,13.1204156 18.4676039,12.806846 L11.3545232,8.63141809 C10.7603912,8.26833741 9.98471883,8.54889976 9.98471883,9.19254279 L9.98471883,17.8404645 C9.98471883,18.5006112 10.7108802,18.7976773 11.3545232,18.4180929 Z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
|
||||||
<script type="text/x-template" id="lyrics-view">
|
|
||||||
<div class="md-body lyric-body">
|
|
||||||
<template v-if="lyrics">
|
|
||||||
<template v-for="lyric in lyrics" v-if="lyric.line != 'lrcInstrumental'">
|
|
||||||
<h3 class="lyric-line" @click="app.seekTo(lyric.startTime, false)"
|
|
||||||
v-bind:class="{ active: app.getLyricClass(lyric.startTime, lyric.endTime)}">
|
|
||||||
{{ lyric.line }}
|
|
||||||
<div class="lyrics-translation" v-if="lyric.translation && lyric.translation != ''">
|
|
||||||
{{ lyric.translation }}
|
|
||||||
<div>
|
|
||||||
</h3>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<h3 class="lyric-line" @click="app.seekTo(lyric.startTime, false)" :start="lyric.startTime"
|
|
||||||
:end="lyric.endTime"
|
|
||||||
v-bind:class="{ active: app.getLyricClass(lyric.startTime, lyric.endTime)}">
|
|
||||||
<div class="lyricWaiting">
|
|
||||||
<div class='WaitingDot1'></div>
|
|
||||||
<div class='WaitingDot2'></div>
|
|
||||||
<div class='WaitingDot3'></div>
|
|
||||||
</div>
|
|
||||||
</h3>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
No Lyrics Available
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
<script src="https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js"></script>
|
|
||||||
<script src="index.js?v=1"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -598,20 +598,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="md-option-line">
|
<div class="md-option-line">
|
||||||
<div class="md-option-segment">
|
<div class="md-option-segment">
|
||||||
{{$root.getLz("settings.option.experimental.closeButtonBehaviour")}}
|
{{$root.getLz("settings.option.experimental.close_button_hide")}}
|
||||||
</div>
|
</div>
|
||||||
<div class="md-option-segment md-option-segment_auto">
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
<select class="md-select" v-model="app.cfg.general.close_behavior" @change="sendDataToMTT()">
|
<input type="checkbox" v-model="app.cfg.general.close_button_hide" switch/>
|
||||||
<option value="0">
|
|
||||||
{{$root.getLz("settings.option.experimental.closeButtonBehaviour.quit")}}
|
|
||||||
</option>
|
|
||||||
<option value="1">
|
|
||||||
{{$root.getLz("settings.option.experimental.closeButtonBehaviour.minimizeTaskbar")}}
|
|
||||||
</option>
|
|
||||||
<option value="2">
|
|
||||||
{{$root.getLz("settings.option.experimental.closeButtonBehaviour.minimizeTray")}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md-option-line">
|
<div class="md-option-line">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue