Merge branch 'develop' into patch-10

This commit is contained in:
Amaru8 2022-04-22 17:16:43 +02:00 committed by GitHub
commit 4c9fbd5a99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 2402 additions and 2330 deletions

View file

@ -22,13 +22,13 @@ jobs:
- restore_cache: - restore_cache:
name: Restore Yarn Package Cache name: Restore Yarn Package Cache
keys: keys:
- yarn-packages-{{ checksum "cider-yarn.lock" }} - yarn-packages-{{ checksum "cider.lock" }}
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- save_cache: - save_cache:
name: Save Yarn Package Cache name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "cider-yarn.lock" }} key: yarn-packages-{{ checksum "cider.lock" }}
paths: paths:
- ~/.cache/yarn - ~/.cache/yarn
- run: - run:

File diff suppressed because it is too large Load diff

View file

@ -35,8 +35,8 @@
"circle:script": "node resources/circle" "circle:script": "node resources/circle"
}, },
"dependencies": { "dependencies": {
"@sentry/electron": "^3.0.2", "@sentry/electron": "^3.0.7",
"@sentry/integrations": "^6.18.1", "@sentry/integrations": "^6.19.6",
"adm-zip": "0.4.10", "adm-zip": "0.4.10",
"castv2-client": "^1.2.0", "castv2-client": "^1.2.0",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
@ -44,22 +44,23 @@
"ejs": "^3.1.6", "ejs": "^3.1.6",
"electron-fetch": "^1.7.4", "electron-fetch": "^1.7.4",
"electron-log": "^4.4.6", "electron-log": "^4.4.6",
"electron-notarize": "^1.1.1", "electron-notarize": "^1.2.1",
"electron-store": "^8.0.1", "electron-store": "^8.0.1",
"electron-updater": "^4.6.5", "electron-updater": "^5.0.1",
"electron-window-state": "^5.0.3", "electron-window-state": "^5.0.3",
"express": "^4.17.3", "express": "^4.17.3",
"get-port": "^5.1.1", "get-port": "^5.1.1",
"jsonc": "^2.0.0", "jsonc": "^2.0.0",
"lastfmapi": "^0.1.1", "lastfmapi": "^0.1.1",
"dns-js": "git+https://github.com/ciderapp/node-dns-js.git",
"mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git", "mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git",
"mpris-service": "^2.1.2", "mpris-service": "^2.1.2",
"music-metadata": "^7.12.1", "music-metadata": "^7.12.3",
"node-gyp": "^8.4.1", "node-gyp": "^9.0.0",
"node-ssdp": "^4.0.1", "node-ssdp": "^4.0.1",
"qrcode": "^1.5.0", "qrcode": "^1.5.0",
"react": "^17.0.2", "react": "^18.0.0",
"react-dom": "^17.0.2", "react-dom": "^18.0.0",
"run-script-os": "^1.1.6", "run-script-os": "^1.1.6",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"v8-compile-cache": "^2.3.0", "v8-compile-cache": "^2.3.0",
@ -69,18 +70,19 @@
"youtube-search-without-api-key": "^1.0.7" "youtube-search-without-api-key": "^1.0.7"
}, },
"devDependencies": { "devDependencies": {
"@types/discord-rpc": "4.0.0", "@types/discord-rpc": "4.0.2",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/qrcode-terminal": "^0.12.0", "@types/qrcode-terminal": "^0.12.0",
"@types/ws": "^8.5.1", "@types/ws": "^8.5.3",
"@types/adm-zip": "^0.5.0",
"electron": "git+https://github.com/castlabs/electron-releases.git", "electron": "git+https://github.com/castlabs/electron-releases.git",
"electron-builder": "^22.14.13", "electron-builder": "^23.0.3",
"electron-builder-notarize-pkg": "^1.2.0", "electron-builder-notarize-pkg": "^1.2.0",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"musickit-typescript": "^1.2.4", "musickit-typescript": "^1.2.4",
"typescript": "^4.6.2", "typescript": "^4.6.3",
"vue-devtools": "^5.1.4", "vue-devtools": "^5.1.4",
"webpack": "~5.69.1" "webpack": "~5.72.0"
}, },
"fileAssociations": [ "fileAssociations": [
{ {

View file

@ -2,7 +2,7 @@
Some notes about Cider's i18n support. Some notes about Cider's i18n support.
- Localization files are stored in jsonc format aka "JSON with Comments" - Localization files are stored in `json` format aka "JavaScript Object Notation".
- The default language is English. - The default language is English.
- 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.
@ -29,7 +29,6 @@ How it is implemented for English:
``` ```
## Localization Notices ## Localization Notices
Several changes have been made to configuration options and will be listed below with the relevant locales that have Several changes have been made to configuration options and will be listed below with the relevant locales that have
@ -190,18 +189,22 @@ Update 28/02/2022 13:00 UTC
* `term.time.day`: Added for `en_US` * `term.time.day`: Added for `en_US`
Update 10/03/2022 14:00 UTC Update 10/03/2022 14:00 UTC
* `settings.header.window`: Added for `en_US` * `settings.header.window`: Added for `en_US`
* `settings.header.window.description`: Added for `en_US` * `settings.header.window.description`: Added for `en_US`
* `settings.option.window.openOnStartup`: Added for `en_US` * `settings.option.window.openOnStartup`: Added for `en_US`
* `settings.option.window.openOnStartup.hidden`: Added for `en_US` * `settings.option.window.openOnStartup.hidden`: Added for `en_US`
Update 20/03/2022 00:01 UTC Update 20/03/2022 00:01 UTC
* `term.creditDesignedBy`: Added for `en_US` * `term.creditDesignedBy`: Added for `en_US`
Update 29/03/2022 04:00 UTC Update 29/03/2022 04:00 UTC
* `settings.option.audio.enableAdvancedFunctionality.ciderPPE.description`: Changed for `en_US` (Deleted for all language files) * `settings.option.audio.enableAdvancedFunctionality.ciderPPE.description`: Changed for `en_US` (Deleted for all language files)
Update 06/04/2022 08:30 UTC Update 06/04/2022 08:30 UTC
* `settings.option.general.customizeSidebar`: Added for `en_US` * `settings.option.general.customizeSidebar`: Added for `en_US`
* `settings.option.general.customizeSidebar.customize`: Added for `en_US` * `settings.option.general.customizeSidebar.customize`: Added for `en_US`
* `settings.option.window.useNativeTitleBar`: Added for `en_US` * `settings.option.window.useNativeTitleBar`: Added for `en_US`
@ -247,6 +250,7 @@ Update 09/04/2022 13:45 UTC
* `action.tray.show`: Changed for `en_US` (Deleted for all language files) * `action.tray.show`: Changed for `en_US` (Deleted for all language files)
Update 14/04/2022 14:30 UTC Update 14/04/2022 14:30 UTC
* `term.variables`: Added for `en_US` * `term.variables`: Added for `en_US`
* `settings.option.connectivity.discordRPC.clientName`: Added for `en_US` * `settings.option.connectivity.discordRPC.clientName`: Added for `en_US`
* `settings.option.connectivity.discordRPC.detailsFormat`: Added for `en_US` * `settings.option.connectivity.discordRPC.detailsFormat`: Added for `en_US`
@ -258,7 +262,12 @@ Update 16/04/2022 9:30 UTC
* `settings.header.connect`: Added for `en_US` * `settings.header.connect`: Added for `en_US`
Update 22/04/2022 14:30 UTC Update 22/04/2022 13:00 UTC
* `settings.option.general.keybindings`: Added for `en_US`
* `settings.option.general.keybindings.open`: Added for `en_US`
Update 22/04/2022 16:00 UTC
* `settings.option.visual.theme.github.openfolder`: Added for `en_US` * `settings.option.visual.theme.github.openfolder`: Added for `en_US`

View file

@ -279,6 +279,8 @@
"settings.option.general.updateCider.branch.develop": "Development", "settings.option.general.updateCider.branch.develop": "Development",
"settings.option.general.customizeSidebar": "Customize Sidebar Items", "settings.option.general.customizeSidebar": "Customize Sidebar Items",
"settings.option.general.customizeSidebar.customize": "Customize", "settings.option.general.customizeSidebar.customize": "Customize",
"settings.option.general.keybindings": "Keybindings",
"settings.option.general.keybindings.open": "Open",
"settings.notyf.updateCider.update-not-available": "No update available", "settings.notyf.updateCider.update-not-available": "No update available",
"settings.notyf.updateCider.update-downloaded": "Update has been downloaded, restart to apply", "settings.notyf.updateCider.update-downloaded": "Update has been downloaded, restart to apply",
"settings.notyf.updateCider.update-error": "Error updating Cider", "settings.notyf.updateCider.update-error": "Error updating Cider",

View file

@ -10,6 +10,7 @@
"notification.updatingLibrarySongs": "Zenekönyvtár frissítése...", "notification.updatingLibrarySongs": "Zenekönyvtár frissítése...",
"notification.updatingLibraryAlbums": "Albumok frissítése...", "notification.updatingLibraryAlbums": "Albumok frissítése...",
"notification.updatingLibraryArtists": "Előadók frissítése...", "notification.updatingLibraryArtists": "Előadók frissítése...",
"term.variables": "Változók",
"term.appleInc": "Apple Inc.", "term.appleInc": "Apple Inc.",
"term.appleMusic": "Apple Music", "term.appleMusic": "Apple Music",
"term.applePodcasts": "Apple Podcasts", "term.applePodcasts": "Apple Podcasts",
@ -278,6 +279,8 @@
"settings.option.general.updateCider.branch.develop": "Fejlesztői", "settings.option.general.updateCider.branch.develop": "Fejlesztői",
"settings.option.general.customizeSidebar": "Oldalsáv elemeinek testreszabása", "settings.option.general.customizeSidebar": "Oldalsáv elemeinek testreszabása",
"settings.option.general.customizeSidebar.customize": "Testreszabás", "settings.option.general.customizeSidebar.customize": "Testreszabás",
"settings.option.general.keybindings": "Billentyűparancsok",
"settings.option.general.keybindings.open": "Megnyitás",
"settings.notyf.updateCider.update-not-available": "Nem található frissítés", "settings.notyf.updateCider.update-not-available": "Nem található frissítés",
"settings.notyf.updateCider.update-downloaded": "A frissítés le lett töltve, a telepítéshez indítsa újra az alkalmazást", "settings.notyf.updateCider.update-downloaded": "A frissítés le lett töltve, a telepítéshez indítsa újra az alkalmazást",
"settings.notyf.updateCider.update-error": "Hiba történt a frissítés közben", "settings.notyf.updateCider.update-error": "Hiba történt a frissítés közben",
@ -387,12 +390,13 @@
"settings.option.lyrics.enableYoutubeLyrics": "YouTube dalszövegek engedélyezése a zenei videóknál", "settings.option.lyrics.enableYoutubeLyrics": "YouTube dalszövegek engedélyezése a zenei videóknál",
"settings.header.connectivity": "Csatlakozások", "settings.header.connectivity": "Csatlakozások",
"settings.header.connectivity.description": "A Cider csatlakozás beállításainak módosítása.", "settings.header.connectivity.description": "A Cider csatlakozás beállításainak módosítása.",
"settings.option.connectivity.discordRPC": "Discord Rich Presence",
"settings.option.connectivity.playbackNotifications": "Lejátszási értesítések", "settings.option.connectivity.playbackNotifications": "Lejátszási értesítések",
"settings.header.connectivity.discordRPC.cider": "Megjelenítés 'Cider'-ként", "settings.option.connectivity.discordRPC": "Discord Rich Presence",
"settings.header.connectivity.discordRPC.appleMusic": "Megjelenítés 'Apple Music'-ként", "settings.option.connectivity.discordRPC.clientName": "Kliensnév",
"settings.option.connectivity.discordRPC.clearOnPause": "Rich Presence törlése megállításnál", "settings.option.connectivity.discordRPC.clearOnPause": "Rich Presence törlése megállításnál",
"settings.option.connectivity.discordRPC.hideButtons": "Rich Presence gombok elrejtése", "settings.option.connectivity.discordRPC.hideButtons": "Rich Presence gombok elrejtése",
"settings.option.connectivity.discordRPC.detailsFormat": "Részletek formátuma",
"settings.option.connectivity.discordRPC.stateFormat": "Állapot formátuma",
"settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling", "settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling",
"settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble késleltetés (%)", "settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble késleltetés (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "Last.fm Now Playing engedélyezése", "settings.option.connectivity.lastfmScrobble.nowPlaying": "Last.fm Now Playing engedélyezése",

View file

@ -279,6 +279,8 @@
"settings.option.general.updateCider.branch.develop": "Development", "settings.option.general.updateCider.branch.develop": "Development",
"settings.option.general.customizeSidebar": "Customize Sidebar Items", "settings.option.general.customizeSidebar": "Customize Sidebar Items",
"settings.option.general.customizeSidebar.customize": "Customize", "settings.option.general.customizeSidebar.customize": "Customize",
"settings.option.general.keybindings": "Keybindings",
"settings.option.general.keybindings.open": "Open",
"settings.notyf.updateCider.update-not-available": "No update available", "settings.notyf.updateCider.update-not-available": "No update available",
"settings.notyf.updateCider.update-downloaded": "Update has been downloaded, restart to apply", "settings.notyf.updateCider.update-downloaded": "Update has been downloaded, restart to apply",
"settings.notyf.updateCider.update-error": "Error updating Cider", "settings.notyf.updateCider.update-error": "Error updating Cider",

View file

@ -14,11 +14,8 @@ import {utils} from './utils';
import {Plugins} from "./plugins"; import {Plugins} from "./plugins";
import {watch} from "chokidar"; import {watch} from "chokidar";
import * as os from "os"; import * as os from "os";
const wallpaper = require('wallpaper'); import wallpaper from "wallpaper";
// @ts-ignore
import * as AdmZip from "adm-zip"; import * as AdmZip from "adm-zip";
import * as util from "util";
/** /**
* @file Creates the BrowserWindow * @file Creates the BrowserWindow
@ -325,7 +322,7 @@ export class BrowserWindow {
this.options.transparent = true; this.options.transparent = true;
} }
this.options.autoHideMenuBar = true this.options.autoHideMenuBar = true
if(utils.getStoreValue("visual.nativeTitleBar")) { if (utils.getStoreValue("visual.nativeTitleBar")) {
this.options.titleBarStyle = "visible"; this.options.titleBarStyle = "visible";
this.options.frame = true this.options.frame = true
} }
@ -333,7 +330,7 @@ export class BrowserWindow {
case "linux": case "linux":
this.options.backgroundColor = "#1E1E1E"; this.options.backgroundColor = "#1E1E1E";
this.options.autoHideMenuBar = true this.options.autoHideMenuBar = true
if(utils.getStoreValue("visual.nativeTitleBar")) { if (utils.getStoreValue("visual.nativeTitleBar")) {
this.options.titleBarStyle = "visible"; this.options.titleBarStyle = "visible";
this.options.frame = true this.options.frame = true
} }
@ -531,6 +528,7 @@ export class BrowserWindow {
app.get("/connect/set-cc-user/:data", (req, res) => { app.get("/connect/set-cc-user/:data", (req, res) => {
//utils.getStoreValue('connectUser', JSON.parse()) // [Connect] Save user in store //utils.getStoreValue('connectUser', JSON.parse()) // [Connect] Save user in store
utils.setStoreValue('connectUser', JSON.parse(req.params.data)) utils.setStoreValue('connectUser', JSON.parse(req.params.data))
utils.getWindow().reload()
res.redirect(`https://connect.cidercollective.dev/linked.html`) res.redirect(`https://connect.cidercollective.dev/linked.html`)
}); });
// [Connect] Set auth URL in store for `shell.openExternal` // [Connect] Set auth URL in store for `shell.openExternal`
@ -552,7 +550,7 @@ export class BrowserWindow {
remote.use(express.static(join(utils.getPath('srcPath'), "./web-remote/"))) remote.use(express.static(join(utils.getPath('srcPath'), "./web-remote/")))
remote.set("views", join(utils.getPath('srcPath'), "./web-remote/views")); remote.set("views", join(utils.getPath('srcPath'), "./web-remote/views"));
remote.set("view engine", "ejs"); remote.set("view engine", "ejs");
getPort({port: 6942}).then((port) => { getPort({port: 6942}).then((port: number) => {
this.remotePort = port; this.remotePort = port;
// Start Remote Discovery // Start Remote Discovery
this.broadcastRemote() this.broadcastRemote()
@ -611,18 +609,19 @@ export class BrowserWindow {
} }
if (details.url.includes("https://qq.com")) { if (details.url.includes("https://qq.com")) {
details.requestHeaders['Accept'] = '*/*', details.requestHeaders['Accept'] = '*/*',
details.requestHeaders['Accept-Encoding'] = 'gzip, deflate, br', details.requestHeaders['Accept-Encoding'] = 'gzip, deflate, br',
details.requestHeaders['Accept-Language'] = 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', details.requestHeaders['Accept-Language'] = 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
details.requestHeaders['Referer'] = 'https://y.qq.com/', details.requestHeaders['Referer'] = 'https://y.qq.com/',
details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 (' details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ('
'KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) '} 'KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) '
}
if (details.url.includes("https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg")) { if (details.url.includes("https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg")) {
details.requestHeaders['Accept'] = '*/*', details.requestHeaders['Accept'] = '*/*',
details.requestHeaders['Accept-Encoding'] = 'gzip, deflate, br', details.requestHeaders['Accept-Encoding'] = 'gzip, deflate, br',
details.requestHeaders['Accept-Language'] = 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', details.requestHeaders['Accept-Language'] = 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 (' details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ('
'KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) ' 'KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) '
details.requestHeaders['Referer'] = "https://y.qq.com/portal/player.html" details.requestHeaders['Referer'] = "https://y.qq.com/portal/player.html"
} }
callback({requestHeaders: details.requestHeaders}); callback({requestHeaders: details.requestHeaders});
} }
@ -647,6 +646,35 @@ export class BrowserWindow {
* ipcMain Events * ipcMain Events
****************************************************************************************************************** */ ****************************************************************************************************************** */
ipcMain.handle("mkv3", async (event, args) => {
const options = {
route: "",
token: "",
mediaToken: "",
GETBody: {}
}
Object.assign(options, args);
let res = await fetch(
`https://amp-api.music.apple.com/${options.route}?${new URLSearchParams({
...options.GETBody
}).toString()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
authorization: `Bearer ${options.token}`,
path: options.route,
authority: "amp-api.music.apple.com",
"media-user-token": options.mediaToken,
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Cider/1.4.2 Chrome/100.0.4896.75 Electron/18.0.3 Safari/537.36"
},
}
);
let json = await res.json();
return json;
})
ipcMain.on("get-wallpaper", async (event) => { ipcMain.on("get-wallpaper", async (event) => {
const wpPath: string = await wallpaper.get(); const wpPath: string = await wallpaper.get();
// get the wallpaper and encode it to base64 then return // get the wallpaper and encode it to base64 then return
@ -1053,21 +1081,21 @@ export class BrowserWindow {
return Math.max(-32768, Math.min(32768, v)); // clamp return Math.max(-32768, Math.min(32768, v)); // clamp
} }
function bitratechange(e: any){ function bitratechange(e: any) {
var t = e.length; var t = e.length;
let sampleRate = 96.0; let sampleRate = 96.0;
let outputSampleRate = 48.0; let outputSampleRate = 48.0;
var s = 0, var s = 0,
o = sampleRate / outputSampleRate, o = sampleRate / outputSampleRate,
u = Math.ceil(t * outputSampleRate / sampleRate), u = Math.ceil(t * outputSampleRate / sampleRate),
a = new Int16Array(u); a = new Int16Array(u);
for (let i = 0; i < u; i++) { for (let i = 0; i < u; i++) {
a[i] = e[Math.floor(s)]; a[i] = e[Math.floor(s)];
s += o; s += o;
} }
return a; return a;
} }
let newaudio = quantization(leftpcm, rightpcm); let newaudio = quantization(leftpcm, rightpcm);
//let newaudio = [leftpcm, rightpcm]; //let newaudio = [leftpcm, rightpcm];

View file

@ -109,8 +109,8 @@ export class Store {
"equalizer": { "equalizer": {
'preset': "default", 'preset': "default",
'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000], 'frequencies': [32, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000],
'gain': [0,0,0,0,0,0,0,0,0,0], 'gain': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'Q': [1,1,1,1,1,1,1,1,1,1], 'Q': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
'mix': 1, 'mix': 1,
'vibrantBass': 0, 'vibrantBass': 0,
'presets': [], 'presets': [],
@ -155,21 +155,29 @@ export class Store {
"AudioContext": false, "AudioContext": false,
"experiments": [], "experiments": [],
"playlistTrackMapping": true "playlistTrackMapping": true
} },
"connectUser": {
"auth": null,
},
} }
private migrations: any = { private migrations: any = {
'>=1.4.3': (store: ElectronStore) => { '>=1.4.3': (store: ElectronStore) => {
if (typeof(store.get('general.discord_rpc')) == 'number' || typeof(store.get('general.discord_rpc')) == 'string') { if (typeof store.get('general.discord_rpc') == 'number' || typeof store.get('general.discord_rpc') == 'string') {
store.delete('general.discord_rpc'); store.delete('general.discord_rpc');
store.set('general.discord_rpc', this.defaults.general.discord_rpc)
} }
}, },
} }
private schema: ElectronStore.Schema<any> = {
"general.discord_rpc": {
type: 'object'
},
}
constructor() { constructor() {
Store.cfg = new ElectronStore({ Store.cfg = new ElectronStore({
name: 'cider-config', name: 'cider-config',
defaults: this.defaults, defaults: this.defaults,
schema: this.schema,
migrations: this.migrations, migrations: this.migrations,
clearInvalidConfig: true clearInvalidConfig: true
}); });

View file

@ -50,12 +50,13 @@ app.on('ready', () => {
}) })
console.log('[Cider][Widevine] Status:', components.status()); console.log('[Cider][Widevine] Status:', components.status());
win.show();
win.on("ready-to-show", () => { win.on("ready-to-show", () => {
Cider.bwCreated(); Cider.bwCreated();
console.debug('[Cider] Window is Ready.') console.debug('[Cider] Window is Ready.')
CiderPlug.callPlugins('onReady', win); CiderPlug.callPlugins('onReady', win);
win.show();
}); });
}); });

View file

@ -137,11 +137,21 @@ export default class DiscordRPC {
} }
}) })
// Checks if the name is greater than 128 because some songs can be that long // Checks if the details is greater than 128 because some songs can be that long
if (activity.details && activity.details.length > 128) { if (activity.details && activity.details.length >= 128) {
activity.details = activity.details.substring(0, 125) + '...' activity.details = activity.details.substring(0, 125) + '...'
} }
// Checks if the state is greater than 128 because some songs can be that long
if (activity.state && activity.state.length >= 128) {
activity.state = activity.state.substring(0, 125) + '...'
}
// Checks if the state is greater than 128 because some songs can be that long
if (activity.largeImageText && activity.largeImageText.length >= 128) {
activity.largeImageText = activity.largeImageText.substring(0, 125) + '...'
}
// Check large image // Check large image
if (activity.largeImageKey == null || activity.largeImageKey === "" || activity.largeImageKey.length > 256) { if (activity.largeImageKey == null || activity.largeImageKey === "" || activity.largeImageKey.length > 256) {
activity.largeImageKey = "cider"; activity.largeImageKey = "cider";
@ -179,7 +189,7 @@ export default class DiscordRPC {
// Set the activity // Set the activity
if (!this._attributes.status && this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) { if (!this._attributes.status && this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) {
this._client.clearActivity() this._client.clearActivity()
} else { } else if (this._activity && this._activityCache !== this._activity && this._activity.details) {
this._client.setActivity(activity) this._client.setActivity(activity)
this._activityCache = this._activity; this._activityCache = this._activity;
} }

View file

@ -102,6 +102,12 @@ export default class Thumbar {
] ]
}, },
{type: 'separator'}, {type: 'separator'},
{
label: 'Toggle Private Session',
accelerator: 'CommandOrControl+P',
click: () => this._win.webContents.executeJavaScript(`app.cfg.general.privateEnabled = !app.cfg.general.privateEnabled`)
},
{type: 'separator'},
{ {
label: 'Web Remote', label: 'Web Remote',
accelerator: 'CommandOrControl+Shift+W', accelerator: 'CommandOrControl+Shift+W',
@ -209,7 +215,7 @@ export default class Thumbar {
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Toggle Developer Tools', label: 'Toggle Developer Tools',
accelerator: 'Option+CommandOrControl+I', accelerator: 'Option+CommandOrControl+Shift+I',
click: () => this._win.webContents.openDevTools() click: () => this._win.webContents.openDevTools()
}, },
{ {

View file

@ -991,6 +991,18 @@
opacity : 0; opacity : 0;
} }
.fade {
transition: opacity 0.15s var(--appleEase);
}
@media (prefers-reduced-motion: reduce) {
.fade {
transition: none;
}
}
.fade:not(.show) {
opacity: 0;
}
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.modal.fade .modal-dialog { .modal.fade .modal-dialog {
transition: none; transition: none;
@ -2424,6 +2436,7 @@ fieldset:disabled .btn {
-webkit-user-drag: none; -webkit-user-drag: none;
// transition: transform .35s var(--appleEase), background-color .35s var(--appleEase); // transition: transform .35s var(--appleEase), background-color .35s var(--appleEase);
font-weight: 500; font-weight: 500;
margin: 0px 4px;
&:hover { &:hover {
// transition: transform .35s var(--appleEase), background-color 0s var(--appleEase); // transition: transform .35s var(--appleEase), background-color 0s var(--appleEase);
background-color: var(--hover); background-color: var(--hover);

View file

@ -1862,3 +1862,106 @@ input[type=checkbox][switch]:checked:active::before {
.search-tab.active { .search-tab.active {
background: var(--keyColor); background: var(--keyColor);
} }
// fancy pills
.nav-pills {
position : relative;
.nav-link {
transition: transform .3s var(--appleEase);
position : relative;
&:after {
--dist: 1px;
content : "";
position : absolute;
top : var(--dist);
bottom : var(--dist);
left : var(--dist);
right : var(--dist);
// width : 100%;
// height : 100%;
background-color: transparent;
border-radius : 50px;
z-index : -1;
opacity : 0;
transition: background-color .5s var(--appleEase), opacity 0.25s var(--appleEase), border-radius .32s var(--appleEase);
}
&:hover {
outline : none;
transform : scale(1.1);
// background: #eee;
background : transparent;
color : #333;
&:after {
opacity: 1;
background-color: #eee;
transition: background-color .25s var(--appleEase),
border-radius .25s var(--appleEase),
color .0s var(--appleEase),
opacity 0.0s var(--appleEase);
}
}
&.active {
outline : none;
transform : scale(1.1);
// background: #eee;
background : transparent;
color : #333;
&:after {
opacity: 1;
background-color: #eee;
}
}
}
&:hover {
.nav-link.active {
outline : none;
transform : scale(1.0);
background: transparent;
color: #eee;
transform : scale(1.0);
&:after {
background : rgb(200 200 200 / 15%);
opacity : 1;
transition: color 0s;
// border-radius: 5px;
--dist: 4px;
}
&:hover {
transform : scale(1.1);
z-index : 1;
color : #333;
&:after {
background: #eee;
border-radius: inherit;
--dist: 1px;
}
}
}
}
&:after {
content : '';
position : absolute;
top : 0;
left : 0;
bottom : 0;
right : 0;
background : rgb(200 200 200 / 10%);
border-radius : 50px;
z-index : 0;
pointer-events: none;
}
}

View file

@ -493,10 +493,51 @@
//background: linear-gradient(180deg, var(--bgColor) 32px, var(--bgColor) 18px, transparent 60px, transparent 100%); //background: linear-gradient(180deg, var(--bgColor) 32px, var(--bgColor) 18px, transparent 60px, transparent 100%);
top : 0; top : 0;
padding-top : var(--navigationBarHeight); padding-top : var(--navigationBarHeight);
display:flex;
flex-direction: column;
height: 100%;
overflow: hidden;
.mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
width: 260px;height:260px;
}
.playlist-body { .playlist-body {
padding : var(--contentInnerPadding) 2em; padding : 32px;
margin-top: -75px; // margin-top: -75px;
overflow-y:overlay;
height:100%;
padding:0px;
background-color: var(--color1);
&.scrollbody {
.tabs {
display: flex;
flex-flow: column;
height: 100%;
.nav-link {
text-transform:capitalize;
}
.tab-content {
height: 100%;
overflow: hidden;
margin:0px;
.tab-pane {
height: 100%;
overflow-y: overlay;
overflow-x:hidden;
padding: var(--contentInnerPadding);
-webkit-mask-image: linear-gradient(180deg, transparent, white 20px);
.well {
margin:0px;
}
}
}
}
}
} }
.floating-header { .floating-header {
@ -510,12 +551,15 @@
background : rgba(0, 0, 0, 0.25); background : rgba(0, 0, 0, 0.25);
top : var(--navigationBarHeight); top : var(--navigationBarHeight);
transition : opacity 0.1s var(--appleEase); transition : opacity 0.1s var(--appleEase);
display: none;
} }
.playlist-display { .playlist-display {
padding : var(--contentInnerPadding); padding : var(--contentInnerPadding);
min-height: 300px; min-height: 300px;
position : relative; position : relative;
box-shadow: 0px 4px 6px 3px rgb(0 0 0 / 10%);
transition: min-height 0.5s ease-in-out;
.artworkContainer { .artworkContainer {
position : absolute; position : absolute;
@ -593,12 +637,14 @@
} }
.playlist-desc { .playlist-desc {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
box-sizing : border-box; box-sizing : border-box;
font-size : 14px; font-size : 14px;
flex-shrink : unset; flex-shrink : unset;
margin-right: 5px; margin-right: 5px;
max-height : 100px; max-height : 100px;
position : relative; position : relative;
height : 4vh;
.content { .content {
height : 4vh; height : 4vh;
@ -695,6 +741,8 @@
font-size: 0.9em; font-size: 0.9em;
margin : 6px; margin : 6px;
opacity : 0.7; opacity : 0.7;
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0.9em;
} }
&.inline-playlist { &.inline-playlist {
@ -739,6 +787,43 @@
} }
} }
} }
.pilldim {
.nav-pills {
width: max-content;
margin: 0 auto;
margin-top: 16px;
}
}
&.plmin {
.playlist-display {
transition: min-height 0.5s ease-in-out;
min-height: 200px;
.playlistInfo {
}
.mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
width: 128px!important;
height: 128px!important;
}
.playlist-time {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0px;
opacity: 0;
}
.playlist-desc {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0px!important;
opacity: 0;
}
}
}
} }
@keyframes playlistArtworkFadeIn { @keyframes playlistArtworkFadeIn {
@ -1064,6 +1149,10 @@
font-size : 2em; font-size : 2em;
} }
.settings-option-body-webview {
height: 100%;
width: 100%;
}
.settings-option-body { .settings-option-body {
margin: 16px; margin: 16px;
} }

View file

@ -1,34 +1,12 @@
const Events = { const Events = {
InitEvents() { InitEvents() {
const app = window.app const app = window.app
// Key binds
document.addEventListener('keydown', function (e) {
if (e.keyCode === 70 && e.ctrlKey) {
app.$refs.searchInput.focus()
app.$refs.searchInput.select()
}
});
// add event listener for when window.location.hash changes // add event listener for when window.location.hash changes
window.addEventListener("hashchange", function () { window.addEventListener("hashchange", function () {
app.appRoute(window.location.hash) app.appRoute(window.location.hash)
}); });
// Key bind to unjam MusicKit in case it fails: CTRL+F10
document.addEventListener('keydown', function (event) {
if (event.ctrlKey && event.keyCode == 121) {
try {
app.mk._services.mediaItemPlayback._currentPlayer.stop()
} catch (e) {
}
try {
app.mk._services.mediaItemPlayback._currentPlayer.destroy()
} catch (e) {
}
}
});
window.addEventListener("mouseup", (e) => { window.addEventListener("mouseup", (e) => {
if (e.button === 3) { if (e.button === 3) {
e.preventDefault() e.preventDefault()
@ -39,7 +17,50 @@ const Events = {
} }
}); });
document.addEventListener('keydown', function (event) { document.addEventListener('keydown', async function (event) {
if (event.keyCode === 70 && event.ctrlKey) {
app.$refs.searchInput.focus()
app.$refs.searchInput.select()
}
// CTRL + R
if (event.keyCode === 82 && event.ctrlKey) {
event.preventDefault()
bootbox.confirm("Reload Cider?", (res)=>{
if(res) {
window.location.reload()
}
})
}
// CTRL + SHIFT + R
if (event.keyCode === 82 && event.ctrlKey && event.shiftKey) {
event.preventDefault()
window.location.reload()
}
// CTRL + E
if (event.keyCode === 69 && event.ctrlKey) {
app.invokeDrawer('queue')
}
// CTRL+H
if (event.keyCode === 72 && event.ctrlKey) {
app.appRoute("home")
}
// CTRL+SHIFT+H
if (event.ctrlKey && event.shiftKey && event.keyCode == 72) {
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
l: app.mklang
})
app.showCollection(hist.data, app.getLz('term.history'))
}
if (event.ctrlKey && event.keyCode == 121) {
try {
app.mk._services.mediaItemPlayback._currentPlayer.stop()
} catch (e) {
}
try {
app.mk._services.mediaItemPlayback._currentPlayer.destroy()
} catch (e) {
}
}
if (event.ctrlKey && event.keyCode == 122) { if (event.ctrlKey && event.keyCode == 122) {
try { try {
ipcRenderer.send('detachDT', '') ipcRenderer.send('detachDT', '')

View file

@ -1,25 +1,39 @@
const MusicKitTools = { const MusicKitTools = {
async v3Continuous ({ async v3Backend({
href, route = "", getBody = {}, options = {}
options = {}, }) {
reqOptions = {}, return await (await ipcRenderer.invoke("mkv3", {
onProgress = () => {}, token: MusicKit.getInstance().developerToken,
onError = () => {}, route: route,
onSuccess = () => {} mediaToken: MusicKit.getInstance().musicUserToken,
} = {}) { GETBody: getBody
}))
},
async v3Continuous({
href,
options = {},
reqOptions = {},
onProgress = () => {
},
onError = () => {
},
onSuccess = () => {
}
} = {}) {
let returnData = [] let returnData = []
async function sendReq(href, options) { async function sendReq(href, options) {
const response = await app.mk.api.v3.music(href, options).catch(error => onError) const response = await app.mk.api.v3.music(href, options).catch(error => onError)
returnData = returnData.concat(response.data.data) returnData = returnData.concat(response.data.data)
if(response.data.next) { if (response.data.next) {
onProgress({ onProgress({
response: response, response: response,
total: returnData.length total: returnData.length
}) })
try { try {
await sendReq(response.data.next, options) await sendReq(response.data.next, options)
}catch(e){ } catch (e) {
await sendReq(response.data.next, options) await sendReq(response.data.next, options)
} }
} }
@ -39,4 +53,4 @@ const MusicKitTools = {
} }
} }
export { MusicKitTools } export {MusicKitTools}

View file

@ -1652,7 +1652,8 @@ const app = new Vue({
params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialNotes,editorialVideo,name,playParams,releaseDate,url,copyright" params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialNotes,editorialVideo,name,playParams,releaseDate,url,copyright"
} }
if (this.cfg.advanced.experiments.includes('inline-playlists')) { // if (this.cfg.advanced.experiments.includes('inline-playlists')) {
if(false) {
let showModal = kind.toString().includes("album") || kind.toString().includes("playlist") let showModal = kind.toString().includes("album") || kind.toString().includes("playlist")
if (app.page.includes("playlist") || app.page.includes("album")) { if (app.page.includes("playlist") || app.page.includes("album")) {
showModal = false showModal = false

View file

@ -12826,6 +12826,19 @@ body.no-gpu .drawertransition-leave-to {
body.no-gpu .lyric-line:hover::after { body.no-gpu .lyric-line:hover::after {
display: none; display: none;
} }
.keybindings-border {
padding-left: 15px;
padding-right: 15px;
border-style: solid;
border-radius: 5px;
border-color: #CBCBCB;
}
.keybinding-text {
width: 95px;
display: flex;
justify-content: center;
align-items: center;
}
.qrimg { .qrimg {
width: -webkit-fill-available; width: -webkit-fill-available;
max-block-size: -webkit-fill-available; max-block-size: -webkit-fill-available;

View file

@ -1228,6 +1228,18 @@ body[platform="darwin"] .app-chrome .app-chrome-item > .window-controls > div.cl
margin-bottom: 15px; margin-bottom: 15px;
} }
} }
// Add Music Video Icons to Songs that are Music Videos
div[data-type="library-music-videos"] .info-rect .title::before,
div[data-type="musicVideo"] .info-rect .title::before {
content: "";
background-image: url(./assets/feather/video.svg);
background-size: contain;
filter:invert(0.6);
display: inline-block;
width: 20px;
height: 20px;
margin-bottom: -4px;
}
.app-chrome .app-chrome-item > .app-playback-controls .song-duration p { .app-chrome .app-chrome-item > .app-playback-controls .song-duration p {
font-weight: 400; font-weight: 400;
@ -3123,6 +3135,21 @@ body.no-gpu {
} }
} }
.keybindings-border {
padding-left: 15px;
padding-right: 15px;
border-style: solid;
border-radius: 5px;
border-color: #CBCBCB;
}
.keybinding-text {
width: 95px;
display: flex;
justify-content: center;
align-items: center;
}
.qrimg { .qrimg {
width: -webkit-fill-available; width: -webkit-fill-available;
max-block-size: -webkit-fill-available; max-block-size: -webkit-fill-available;

View file

@ -1,5 +1,4 @@
<script type="text/x-template" id="add-to-playlist"> <script type="text/x-template" id="add-to-playlist">
<template>
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()"> <div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()" @contextmenu.self="app.resetState()">
<div class="modal-window"> <div class="modal-window">
<div class="modal-header"> <div class="modal-header">
@ -30,7 +29,6 @@
</div> </div>
</div> </div>
</div> </div>
</template>
</script> </script>
<script> <script>
@ -65,7 +63,7 @@
}, },
methods: { methods: {
playlistSelect(playlist) { playlistSelect(playlist) {
if(playlist.type != "library-playlist-folders") { if (playlist.type != "library-playlist-folders") {
this.addToPlaylist(playlist.id) this.addToPlaylist(playlist.id)
} }
}, },

View file

@ -1,5 +1,5 @@
<script type="text/x-template" id="mediaitem-scroller-horizontal"> <script type="text/x-template" id="mediaitem-scroller-horizontal">
<vue-horizontal> <vue-horizontal ref="horizontal">
<slot></slot> <slot></slot>
<mediaitem-square :key="item?.id ?? ''" :kind="kind" :item="item" v-for="item in items"></mediaitem-square> <mediaitem-square :key="item?.id ?? ''" :kind="kind" :item="item" v-for="item in items"></mediaitem-square>
</vue-horizontal> </vue-horizontal>
@ -24,6 +24,9 @@
app: this.$root, app: this.$root,
} }
}, },
mounted() {
// this.$refs.horizontal.refresh()
},
methods: {} methods: {}
}); });
</script> </script>

View file

@ -40,7 +40,7 @@
relateMediaItems: { relateMediaItems: {
type: Array, type: Array,
required: false, required: false,
default () { default() {
return [] return []
} }
} }
@ -62,30 +62,33 @@
this.icon = await this.$root.getSvgIcon("./assets/feather/folder.svg") this.icon = await this.$root.getSvgIcon("./assets/feather/folder.svg")
} }
let playlistMap = this.$root.playlists.trackMapping let playlistMap = this.$root.playlists.trackMapping
if(this.relateMediaItems.length != 0) { if (this.relateMediaItems.length != 0) {
if(playlistMap[this.relateMediaItems[0]].includes(this.item.id)) { if (playlistMap[this.relateMediaItems[0]]) {
this.hasRelatedMediaItems = true if (playlistMap[this.relateMediaItems[0]].includes(this.item.id)) {
this.hasRelatedMediaItems = true
}
} }
} }
}, },
methods: { methods: {
clickEvent() { clickEvent() {
if(this.item.type != "library-playlist-folders") { if (this.item.type != "library-playlist-folders") {
if(this.playlistSelect) { if (this.playlistSelect) {
this.playlistSelect(this.item) this.playlistSelect(this.item)
}else{ } else {
this.openPlaylist(this.item) this.openPlaylist(this.item)
} }
}else{ } else {
this.getPlaylistChildren(this.item) this.getPlaylistChildren(this.item)
} }
}, },
rename() { rename() {
this.renaming = false this.renaming = false
if(this.item.type === "library-playlist-folders") { if (this.item.type === "library-playlist-folders") {
this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name) this.$root.editPlaylistFolder(this.item.id, this.item.attributes.name)
}else{ } else {
this.$root.editPlaylist(this.item.id, this.item.attributes.name) this.$root.editPlaylist(this.item.id, this.item.attributes.name)
} }
}, },
@ -93,7 +96,7 @@
let self = this let self = this
this.children = [] this.children = []
this.children = this.$root.playlists.listing.filter(child => { this.children = this.$root.playlists.listing.filter(child => {
if(child.parent == self.item.id) { if (child.parent == self.item.id) {
return child return child
} }
}) })
@ -117,13 +120,13 @@
// find the item in this.$root.playlists.listing and store it in a variable // find the item in this.$root.playlists.listing and store it in a variable
this.$root.playlists.listing.filter(playlist => { this.$root.playlists.listing.filter(playlist => {
if(playlist.id == item.id) { if (playlist.id == item.id) {
console.log(playlist) console.log(playlist)
playlist.parent = sendTo.id playlist.parent = sendTo.id
} }
}) })
if(typeof this.$parent.getChildren == "function") { if (typeof this.$parent.getChildren == "function") {
this.$parent.getChildren() this.$parent.getChildren()
console.log(this.$parent.children) console.log(this.$parent.children)
} }
@ -142,14 +145,14 @@
id: this.playlistRoot, id: this.playlistRoot,
type: "library-playlist-folders" type: "library-playlist-folders"
}) })
setTimeout(()=>{self.getChildren()}, 2000) setTimeout(() => { self.getChildren() }, 2000)
} }
}, },
"rename": { "rename": {
name: this.$root.getLz('action.rename'), name: this.$root.getLz('action.rename'),
action: () => { action: () => {
this.renaming = true this.renaming = true
setTimeout(()=>{ setTimeout(() => {
document.querySelector(".pl-rename-field").focus() document.querySelector(".pl-rename-field").focus()
document.querySelector(".pl-rename-field").select() document.querySelector(".pl-rename-field").select()
}, 100) }, 100)
@ -171,7 +174,7 @@
} }
} }
} }
if(this.item.type === "library-playlist-folders") { if (this.item.type === "library-playlist-folders") {
menu.items.addToFavorites.disabled = true menu.items.addToFavorites.disabled = true
} }
app.showMenuPanel(menu, event) app.showMenuPanel(menu, event)
@ -180,23 +183,23 @@
evt.preventDefault(); evt.preventDefault();
evt.dataTransfer.dropEffect = "move"; evt.dataTransfer.dropEffect = "move";
}, },
onDrop (evt) { onDrop(evt) {
let data = JSON.parse(evt.dataTransfer.getData("text/plain")) let data = JSON.parse(evt.dataTransfer.getData("text/plain"))
evt.preventDefault(); evt.preventDefault();
if(data.id == this.item.id) { if (data.id == this.item.id) {
return; return;
} }
console.log(data) console.log(data)
if(data) { if (data) {
if(this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") { if (this.item.type == "library-playlists" || this.item.type == "library-playlist-folders") {
if(data.type == "library-playlists" && this.item.type == "library-playlists") { if (data.type == "library-playlists" && this.item.type == "library-playlists") {
return return
} }
this.move(data, this.item) this.move(data, this.item)
} }
} }
}, },
startDrag (evt) { startDrag(evt) {
evt.dataTransfer.dropEffect = 'move' evt.dataTransfer.dropEffect = 'move'
evt.dataTransfer.effectAllowed = 'move' evt.dataTransfer.effectAllowed = 'move'
evt.dataTransfer.setData('text/plain', JSON.stringify(this.item)) evt.dataTransfer.setData('text/plain', JSON.stringify(this.item))
@ -215,7 +218,7 @@
this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => { this.$root.mk.api.v3.music(`v1/me/library/playlist-folders/${item.id}/children`).then(data => {
let children = data.data.data; let children = data.data.data;
children.forEach(child => { children.forEach(child => {
if(!self.$root.playlists.listing.find(listing => listing.id == child.id)) { if (!self.$root.playlists.listing.find(listing => listing.id == child.id)) {
child.parent = self.item.id child.parent = self.item.id
self.$root.playlists.listing.push(child) self.$root.playlists.listing.push(child)
} }
@ -234,9 +237,9 @@
}) })
}, },
isPlaylistSelected(item) { isPlaylistSelected(item) {
if(this.$root.showingPlaylist.id == item.id) { if (this.$root.showingPlaylist.id == item.id) {
return ["active"] return ["active"]
} else { } else {
return [] return []
} }
}, },

View file

@ -5,7 +5,7 @@
<div class="settings-option-body"> <div class="settings-option-body">
<div class="md-option-line"> <div class="md-option-line">
<b-jumbotron :header="$root.getLz('settings.option.audio.audioLab')" <b-jumbotron :header="$root.getLz('settings.option.audio.audioLab')"
lead="$root.getLz('settings.option.audio.audioLab.subheader')"></b-jumbotron> :lead="$root.getLz('settings.option.audio.audioLab.subheader')"></b-jumbotron>
</div> </div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === false"> <div class="md-option-line" v-show="app.cfg.advanced.AudioContext === false">
<div class="md-option-segment"> <div class="md-option-segment">

View file

@ -1,5 +1,6 @@
<script type="text/x-template" id="cider-playlist"> <script type="text/x-template" id="cider-playlist">
<div class="content-inner playlist-page" v-if="data != [] && data.attributes != null" <div class="content-inner playlist-page" :class="classes" v-if="data != [] && data.attributes != null"
:style="{'--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : ''}"> :style="{'--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : ''}">
<template v-if="app.playlists.loadingState == 0"> <template v-if="app.playlists.loadingState == 0">
<div class="content-inner centered"> <div class="content-inner centered">
@ -8,14 +9,15 @@
</template> </template>
<template v-if="app.playlists.loadingState == 1"> <template v-if="app.playlists.loadingState == 1">
<div class="playlist-display" <div class="playlist-display"
@mouseover.self="minClass(false)"
:style="{ :style="{
'--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '', '--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '',
'--textColor': (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : '' '--textColor': (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : ''
}"> }">
<div class="playlistInfo"> <div class="playlistInfo">
<div class="row"> <div class="row">
<div class="col-auto flex-center"> <div class="col-auto flex-center" @mouseover="minClass(false)">
<div style="width: 260px;height:260px;"> <div class="mediaContainer">
<mediaitem-artwork <mediaitem-artwork
shadow="large" shadow="large"
:video-priority="true" :video-priority="true"
@ -28,11 +30,11 @@
<div class="col playlist-info"> <div class="col playlist-info">
<template v-if="!editorialNotesExpanded"> <template v-if="!editorialNotesExpanded">
<div> <div>
<div class="playlist-name" @click="editPlaylistName()" v-show="!nameEditing"> <div class="playlist-name" @mouseover="minClass(false)" @click="editPlaylistName()" v-show="!nameEditing">
{{data.attributes ? (data.attributes.name ?? {{data.attributes ? (data.attributes.name ??
(data.attributes.title ?? '') ?? '') : ''}} (data.attributes.title ?? '') ?? '') : ''}}
</div> </div>
<div class="playlist-name" v-show="nameEditing"><input type="text" <div class="playlist-name" @mouseover="minClass(false)" v-show="nameEditing"><input type="text"
spellcheck="false" spellcheck="false"
class="nameEdit" class="nameEdit"
v-model="data.attributes.name" v-model="data.attributes.name"
@ -50,11 +52,15 @@
<artist-chip v-for="artist in data.relationships.artists?.data" <artist-chip v-for="artist in data.relationships.artists?.data"
:item="artist"></artist-chip> :item="artist"></artist-chip>
</template> </template>
<div class="playlist-desc" v-if="(data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)) || (data.attributes.editorialNotes && (data.attributes.editorialNotes.standard || data.attributes.editorialNotes.short))"> <div class="playlist-desc"
<div v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short) != null" class="content" v-if="(data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)) || (data.attributes.editorialNotes && (data.attributes.editorialNotes.standard || data.attributes.editorialNotes.short))">
v-html="data.attributes.description?.short ?? data.attributes.editorialNotes?.short" @click="openInfoModal()"></div> <div v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short) != null"
<div v-else-if="(data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null" class="content" class="content"
v-html="data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard"></div> v-html="data.attributes.description?.short ?? data.attributes.editorialNotes?.short"
@click="openInfoModal()"></div>
<div v-else-if="(data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null"
class="content"
v-html="data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard"></div>
<!-- <button v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short ) != null" class="more-btn" <!-- <button v-if="(data.attributes.description?.short ?? data.attributes.editorialNotes?.short ) != null" class="more-btn"
@click="editorialNotesExpanded = !editorialNotesExpanded"> @click="editorialNotesExpanded = !editorialNotesExpanded">
{{app.getLz('term.showMore')}} {{app.getLz('term.showMore')}}
@ -142,78 +148,93 @@
</div> </div>
</div> </div>
</div> </div>
<div class="playlist-body"> <div class="playlist-body scrollbody">
<div class="well">
<div style="width:100%"> <b-tabs pills class="track-pills pilldim" align="center" content-class="mt-3">
<draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'" <b-tab :title="$root.getLz('term.tracks')">
v-model="data.relationships.tracks.data" @start="drag=true" @end="drag=false;put()"> <div @wheel="minClass(true)" @scroll="minClass(true)">
<template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1"> <div class="">
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" <div style="width:100%" @click="minClass(true)">
:showIndex="true" <draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'"
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')" v-model="data.relationships.tracks.data" @start="drag=true"
:context-ext="buildContextMenu()" @end="drag=false;put()">
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item> <template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1">
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
:showIndex="true"
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
:context-ext="buildContextMenu()"
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
</template> </template>
<template v-else> <template v-else>
<div v-for="disc in nestedPlaylist"> <div v-for="disc in nestedPlaylist">
<div class="playlist-time">{{($root.getLz("term.discNumber") ?? "").replace("${discNumber}",disc.disc)}}</div> <div class="playlist-time">{{($root.getLz("term.discNumber") ??
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" "").replace("${discNumber}",disc.disc)}}
:showIndex="true" </div>
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')" <mediaitem-list-item :item="item" :parent="getItemParent(data)"
:context-ext="buildContextMenu()" :index="index"
v-for="(item,index) in disc.tracks"></mediaitem-list-item> :showIndex="true"
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
:context-ext="buildContextMenu()"
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
</div> </div>
</template> </template>
</draggable> </draggable>
</div> </div>
</div> </div>
<div class="friends-info" v-if="itemBadges.length != 0"> <div class="friends-info" v-if="itemBadges.length != 0">
<div class="well"> <div class="well">
<div class="badge-container"> <div class="badge-container">
<div class="socialBadge" :title="`${badge.attributes.name} - @${badge.attributes.handle}`" <div class="socialBadge"
v-for="badge in itemBadges"> :title="`${badge.attributes.name} - @${badge.attributes.handle}`"
<mediaitem-artwork v-for="badge in itemBadges">
:url="badge.attributes.artwork.url" <mediaitem-artwork
:size="60"></mediaitem-artwork> :url="badge.attributes.artwork.url"
:size="60"></mediaitem-artwork>
</div>
</div>
</div> </div>
</div> </div>
</div> <div class="playlist-time">
</div> {{getFormattedDate()}}
<div class="playlist-time">
{{getFormattedDate()}}
</div>
<div class="playlist-time total">{{app.getTotalTime()}}</div>
<div class="playlist-time item-navigate" @click="app.searchAndNavigate(data,'recordLabel') "
style="width: 50%;">
{{data.attributes.copyright}}
</div>
<template
v-if="(data.attributes?.playParams?.kind ?? data.type ?? '').includes('album') && data.relationships.catalog != null && data.relationships.catalog != null && data.relationships.catalog.data.length > 0">
<div class="playlist-time showExtended item-navigate" style="color:#fa586a; font-weight: bold"
@click="app.routeView(data.relationships.catalog.data[0])">
{{$root.getLz("action.showAlbum")}}
</div>
</template>
<hr>
<template v-if="typeof data.meta != 'undefined'">
<div v-for="view in data.meta.views.order" v-if="data.views[view].data.length != 0">
<div class="row">
<div class="col">
<h3>{{ data.views[view].attributes.title }}</h3>
</div>
</div> </div>
<div class="row"> <div class="playlist-time total">{{app.getTotalTime()}}</div>
<div class="col"> <div class="playlist-time item-navigate" @click="app.searchAndNavigate(data,'recordLabel') "
<mediaitem-scroller-horizontal style="width: 50%;">
:items="data.views[view].data"></mediaitem-scroller-horizontal> {{data.attributes.copyright}}
</div>
</div> </div>
</div> <template
</template> v-if="(data.attributes?.playParams?.kind ?? data.type ?? '').includes('album') && data.relationships.catalog != null && data.relationships.catalog != null && data.relationships.catalog.data.length > 0">
<div class="playlist-time showExtended item-navigate"
style="color:#fa586a; font-weight: bold"
@click="app.routeView(data.relationships.catalog.data[0])">
{{$root.getLz("action.showAlbum")}}
</div>
</template>
</div>
</b-tab>
<template v-if="typeof data.views != 'undefined'">
<b-tab lazy :title="data.views[view].attributes.title" v-for="view in data.meta.views.order"
v-if="data.views[view].data.length != 0">
<div >
<div class="row">
<div class="col">
<h3>{{ data.views[view].attributes.title }}</h3>
</div>
</div>
<div class="row">
<div class="col">
<mediaitem-scroller-horizontal
:items="data.views[view].data"></mediaitem-scroller-horizontal>
</div>
</div>
</div>
</b-tab>
</template>
</b-tabs>
</div> </div>
</template> </template>
</div> </div>
@ -238,6 +259,7 @@
headerVisible: true, headerVisible: true,
useArtistChip: false, useArtistChip: false,
nestedPlaylist: [], nestedPlaylist: [],
classes: [],
} }
}, },
mounted: function () { mounted: function () {
@ -254,31 +276,41 @@
} }
}, },
methods: { methods: {
openInfoModal(){ minClass(val) {
if (val) {
this.classes = ["plmin"]
} else {
this.classes = []
}
},
openInfoModal() {
app.moreinfodata = []; app.moreinfodata = [];
app.moreinfodata = { app.moreinfodata = {
title : this.data?.attributes ? (this.data?.attributes?.name ?? title: this.data?.attributes ? (this.data?.attributes?.name ??
(this.data?.attributes?.title ?? '') ?? '') : '', (this.data?.attributes?.title ?? '') ?? '') : '',
subtitle: this.data?.attributes?.artistName ?? '', subtitle: this.data?.attributes?.artistName ?? '',
content: ((this.data?.attributes?.editorialNotes != null ) ? (this.data?.attributes?.editorialNotes?.standard ?? (this.data?.attributes?.editorialNotes?.short ?? '') ) : (data.attributes?.description ? (this.data.attributes?.description?.standard ?? (this.data?.attributes?.description?.short ?? '')) : '')) content: ((this.data?.attributes?.editorialNotes != null) ? (this.data?.attributes?.editorialNotes?.standard ?? (this.data?.attributes?.editorialNotes?.short ?? '')) : (data.attributes?.description ? (this.data.attributes?.description?.standard ?? (this.data?.attributes?.description?.short ?? '')) : ''))
} }
app.modals.moreInfo = true; app.modals.moreInfo = true;
}, },
generateNestedPlaylist(){ generateNestedPlaylist() {
this.nestedPlaylist = []; this.nestedPlaylist = [];
if (this.data?.type?.includes("album")){ if (this.data?.type?.includes("album")) {
console.log(this.data.relationships.tracks.data) console.log(this.data.relationships.tracks.data)
let songlists = this.data.relationships.tracks.data; let songlists = this.data.relationships.tracks.data;
let discs = songlists.map(x => {return x.attributes.discNumber}).filter((item, i, ar) => ar.indexOf(item) === i); let discs = songlists.map(x => {
if (discs && discs.length > 1){ return x.attributes.discNumber
for (disc of discs){ }).filter((item, i, ar) => ar.indexOf(item) === i);
let songs = songlists.filter(x => x.attributes.discNumber == disc); if (discs && discs.length > 1) {
this.nestedPlaylist.push({disc: disc, tracks: songs}) for (disc of discs) {
let songs = songlists.filter(x => x.attributes.discNumber == disc);
this.nestedPlaylist.push({disc: disc, tracks: songs})
}
} }
} console.log(this.nestedPlaylist)
console.log(this.nestedPlaylist)
}}, }
},
isHeaderVisible(visible) { isHeaderVisible(visible) {
this.headerVisible = visible this.headerVisible = visible
}, },
@ -462,19 +494,70 @@
} }
}) })
}, },
menu(event) { async menu(event) {
let self = this let self = this
let artistId = null let artistId = null
if(typeof this.data.relationships.artists != "undefined") { if (typeof this.data.relationships.artists != "undefined") {
artistId = this.data.relationships.artists.data[0].id artistId = this.data.relationships.artists.data[0].id
if(this.data.relationships.artists.data[0].type == "library-artists") { if (this.data.relationships.artists.data[0].type == "library-artists") {
artistId = this.data.relationships.artists.data[0].relationships.catalog.data[0].id artistId = this.data.relationships.artists.data[0].relationships.catalog.data[0].id
} }
} }
let menuItems = { let menuItems = {
headerItems: [
{
"icon": "./assets/feather/heart.svg",
"id": "love",
"name": app.getLz('action.love'),
"hidden": false,
"disabled": true,
"action": function () {
app.love(self.data)
}
},
{
"icon": "./assets/feather/heart.svg",
"id": "unlove",
"active": true,
"name": app.getLz('action.unlove'),
"hidden": true,
"action": function () {
app.unlove(self.data)
}
},
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "dislike",
"name": app.getLz('action.dislike'),
"hidden": false,
"disabled": true,
"action": function () {
app.dislike(self.data)
}
},
{
"icon": "./assets/feather/thumbs-down.svg",
"id": "undo_dislike",
"name": app.getLz('action.undoDislike'),
"active": true,
"hidden": true,
"action": function () {
app.unlove(self.data)
}
},
],
items: { items: {
"addToPlaylist": {
name: app.getLz('action.addToPlaylist'),
"icon": "./assets/feather/list.svg",
action: () => {
app.selectedMediaItems = []
app.select_selectMediaItem(this.data.attributes.playParams.id ?? this.data.id, this.data.attributes.playParams.kind ?? this.data.type, 0, 0, this.data.attributes.playParams.isLibrary ?? false)
app.promptAddToPlaylist()
}
},
"share": { "share": {
name: app.getLz('term.share'), name: app.getLz('term.share'),
icon: "./assets/feather/share.svg", icon: "./assets/feather/share.svg",
@ -521,23 +604,36 @@
}, },
} }
} }
app.showMenuPanel(menuItems, event)
if(artistId != null) { if (artistId != null) {
if(app.followingArtist(artistId)){ if (app.followingArtist(artistId)) {
menuItems.items.follow.hidden = true menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = false menuItems.items.unfollow.hidden = false
} else { } else {
menuItems.items.follow.hidden = false menuItems.items.follow.hidden = false
menuItems.items.unfollow.hidden = true menuItems.items.unfollow.hidden = true
} }
}else{ } else {
menuItems.items.follow.hidden = true menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = true menuItems.items.unfollow.hidden = true
} }
try {
let rating = await app.getRating(self.data)
if (rating == 0) {
menuItems.headerItems.find(x => x.id == 'love').disabled = false
menuItems.headerItems.find(x => x.id == 'dislike').disabled = false
} else if (rating == 1) {
menuItems.headerItems.find(x => x.id == 'unlove').hidden = false
menuItems.headerItems.find(x => x.id == 'love').hidden = true
} else if (rating == -1) {
menuItems.headerItems.find(x => x.id == 'undo_dislike').hidden = false
menuItems.headerItems.find(x => x.id == 'dislike').hidden = true
}
} catch (err) {
}
app.showMenuPanel(menuItems, event)
}, },
getItemParent: function (data) { getItemParent: function (data) {
kind = data.attributes.playParams.kind; kind = data.attributes.playParams.kind;

View file

@ -151,78 +151,85 @@
</div> </div>
</div> </div>
</div> </div>
<div class="playlist-body"> <div class="playlist-body scrollbody">
<div class="well">
<div style="width:100%"> <b-tabs pills align="center" content-class="mt-3">
<draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'" <b-tab title="Tracks">
v-model="data.relationships.tracks.data" @start="drag=true" <div class="">
@end="drag=false;put()"> <div style="width:100%">
<template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1"> <draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'"
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" v-model="data.relationships.tracks.data" @start="drag=true" @end="drag=false;put()">
:showIndex="true" <template v-if="nestedPlaylist == [] || nestedPlaylist.length <= 1">
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')" <mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
:context-ext="buildContextMenu()" :showIndex="true"
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item> :showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
</template> :context-ext="buildContextMenu()"
<template v-else> v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
<div v-for="disc in nestedPlaylist"> </template>
<div class="playlist-time">{{($root.getLz("term.discNumber") ?? "").replace("${discNumber}",disc.disc)}}</div> <template v-else>
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" <div v-for="disc in nestedPlaylist">
:showIndex="true" <div class="playlist-time">{{($root.getLz("term.discNumber") ?? "").replace("${discNumber}",disc.disc)}}</div>
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')" <mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
:context-ext="buildContextMenu()" :showIndex="true"
v-for="(item,index) in disc.tracks"></mediaitem-list-item> :showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
:context-ext="buildContextMenu()"
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
</div>
</template>
</draggable>
</div>
</div>
<div class="friends-info" v-if="itemBadges.length != 0">
<div class="well">
<div class="badge-container">
<div class="socialBadge" :title="`${badge.attributes.name} - @${badge.attributes.handle}`"
v-for="badge in itemBadges">
<mediaitem-artwork
:url="badge.attributes.artwork.url"
:size="60"></mediaitem-artwork>
</div>
</div> </div>
</template>
</draggable>
</div>
</div>
<div class="friends-info" v-if="itemBadges.length != 0">
<div class="well">
<div class="badge-container">
<div class="socialBadge"
:title="`${badge.attributes.name} - @${badge.attributes.handle}`"
v-for="badge in itemBadges">
<mediaitem-artwork
:url="badge.attributes.artwork.url"
:size="60"></mediaitem-artwork>
</div> </div>
</div> </div>
</div> <div class="playlist-time">
</div> {{getFormattedDate()}}
<div class="playlist-time"> </div>
{{getFormattedDate()}} <div class="playlist-time total">{{app.getTotalTime()}}</div>
</div> <div class="playlist-time item-navigate" @click="app.searchAndNavigate(data,'recordLabel') "
<div class="playlist-time total">{{app.getTotalTime()}}</div> style="width: 50%;">
<div class="playlist-time item-navigate" @click="app.searchAndNavigate(data,'recordLabel') " {{data.attributes.copyright}}
style="width: 50%;"> </div>
{{data.attributes.copyright}} <template
</div> v-if="(data.attributes?.playParams?.kind ?? data.type ?? '').includes('album') && data.relationships.catalog != null && data.relationships.catalog != null && data.relationships.catalog.data.length > 0">
<template <div class="playlist-time showExtended item-navigate" style="color:#fa586a; font-weight: bold"
v-if="(data.attributes?.playParams?.kind ?? data.type ?? '').includes('album') && data.relationships.catalog != null && data.relationships.catalog != null && data.relationships.catalog.data.length > 0"> @click="app.routeView(data.relationships.catalog.data[0])">
<div class="playlist-time showExtended item-navigate" style="color:#fa586a; font-weight: bold" {{$root.getLz("action.showAlbum")}}
@click="app.routeView(data.relationships.catalog.data[0])"> </div>
{{$root.getLz("action.showAlbum")}} </template>
</div> <hr>
</template> </b-tab>
<hr> <template v-if="typeof data.views != 'undefined'">
<template v-if="typeof data.meta != 'undefined'"> <b-tab lazy :title="data.views[view].attributes.title" v-for="view in data.meta.views.order" v-if="data.views[view].data.length != 0">
<div v-for="view in data.meta.views.order" v-if="data.views[view].data.length != 0"> <div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<h3>{{ data.views[view].attributes.title }}</h3> <h3>{{ data.views[view].attributes.title }}</h3>
</div> </div>
</div> </div>
<div> <div class="row">
<mediaitem-scroller-horizontal <div class="col">
:items="data.views[view].data"></mediaitem-scroller-horizontal> <mediaitem-scroller-horizontal
:items="data.views[view].data"></mediaitem-scroller-horizontal>
</div>
</div> </div>
</div> </div>
</template> </b-tab>
</template>
</b-tabs>
</div> </div>
</template> </template>
</div> </div>

View file

@ -123,6 +123,68 @@
</div> </div>
</b-modal> </b-modal>
</div> </div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.general.keybindings')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn" v-b-modal.modal-2>
{{$root.getLz('settings.option.general.keybindings.open')}}
</button>
</div>
<b-modal id="modal-2" centered size="lg" v-title="$root.getLz('settings.option.general.keybindings')" ok-only>
<div class="settings-option-body">
<div class="md-option-line">
<div class="md-option-segment">
Toggle Private Session
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + P</p>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Web Remote
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + Shift + W</p>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Audio Settings
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + Shift + A</p>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Plugin Menu
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + Shift + P</p>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Cast to Devices
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + Shift + C</p>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
Open Developer Tools
</div>
<div class="md-option-segment md-option-segment_auto keybindings-border">
<p class="keybinding-text">{{ getCommandOrControl() }} + {{ getOptionOrShift() }} + I</p>
</div>
</div>
</div>
</b-modal>
</div>
</div> </div>
</div> </div>
</b-tab> </b-tab>
@ -919,7 +981,7 @@
{{$root.getLz('settings.option.experimental.inline_playlists')}} {{$root.getLz('settings.option.experimental.inline_playlists')}}
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<input type="checkbox" v-model="app.cfg.advanced.experiments.includes('inline-playlists')" @click="app.cfg.advanced.experiments.includes('inline-playlists') ? removeExperiment('inline-playlists') : addExperiment('inline-playlists')" switch/> <input type="checkbox" disabled v-model="app.cfg.advanced.experiments.includes('inline-playlists')" @click="app.cfg.advanced.experiments.includes('inline-playlists') ? removeExperiment('inline-playlists') : addExperiment('inline-playlists')" switch/>
</div> </div>
</div> </div>
@ -982,8 +1044,8 @@
<div class="md-option-header"> <div class="md-option-header">
<span>{{$root.getLz('settings.header.connect')}}</span> <span>{{$root.getLz('settings.header.connect')}}</span>
</div> </div>
<div class="settings-option-body"> <div class="settings-option-body-webview">
<div class="md-option-line update-check"> <div class="md-option-line update-check" v-if="app.cfg.connectUser == null">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connect.link_account')}} {{$root.getLz('settings.option.connect.link_account')}}
<small>{{$root.getLz('settings.option.connect.link_account.description')}}</small> <small>{{$root.getLz('settings.option.connect.link_account.description')}}</small>
@ -996,9 +1058,11 @@
</button> </button>
</div> </div>
</div> </div>
<div v-if="app.cfg.connectUser != null" style="display:inline-flex; width:100%;height: 100%">
<iframe :src="`https://connect.cidercollective.dev/setSession/` + encodeURI(JSON.stringify(app.cfg.connectUser))" sandbox="allow-scripts allow-top-navigation allow-same-origin" width="100%" height="100%" frameborder="0"></iframe>
</div>
</div> </div>
</div> </div>
</div>
</b-tab> </b-tab>
</b-tabs> </b-tabs>
</div> </div>
@ -1124,6 +1188,12 @@
} }
}, },
methods: { methods: {
getCommandOrControl() {
return app.platform == "darwin" ? "⌘" : "Ctrl";
},
getOptionOrShift() {
return app.platform == "darwin" ? "⌥" : "Shift";
},
windowBgStyleChange() { windowBgStyleChange() {
this.$root.getNowPlayingArtworkBG(undefined, true) this.$root.getNowPlayingArtworkBG(undefined, true)
if (this.$root.cfg.visual.window_background_style == "mica") { if (this.$root.cfg.visual.window_background_style == "mica") {