commit
483098215e
21 changed files with 510 additions and 187 deletions
|
@ -40,6 +40,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/electron": "^3.0.7",
|
"@sentry/electron": "^3.0.7",
|
||||||
"@sentry/integrations": "^6.19.6",
|
"@sentry/integrations": "^6.19.6",
|
||||||
|
"@types/pouchdb": "^6.4.0",
|
||||||
|
"@types/pouchdb-node": "^6.1.4",
|
||||||
"adm-zip": "0.4.10",
|
"adm-zip": "0.4.10",
|
||||||
"airtunes2": "git+https://github.com/ciderapp/node_airtunes2",
|
"airtunes2": "git+https://github.com/ciderapp/node_airtunes2",
|
||||||
"castv2-client": "^1.2.0",
|
"castv2-client": "^1.2.0",
|
||||||
|
@ -58,16 +60,21 @@
|
||||||
"jimp": "^0.16.1",
|
"jimp": "^0.16.1",
|
||||||
"jsonc": "^2.0.0",
|
"jsonc": "^2.0.0",
|
||||||
"lastfmapi": "^0.1.1",
|
"lastfmapi": "^0.1.1",
|
||||||
|
"level": "^8.0.0",
|
||||||
"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.3",
|
"music-metadata": "^7.12.3",
|
||||||
"node-gyp": "^9.0.0",
|
"node-gyp": "^9.0.0",
|
||||||
"node-ssdp": "^4.0.1",
|
"node-ssdp": "^4.0.1",
|
||||||
|
"pouchdb-adapter-leveldb": "^7.3.0",
|
||||||
|
"pouchdb-node": "^7.3.0",
|
||||||
|
"pouchdb-upsert": "^2.2.0",
|
||||||
"qrcode": "^1.5.0",
|
"qrcode": "^1.5.0",
|
||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"react-dom": "^18.0.0",
|
"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",
|
||||||
|
"ts-md5": "^1.2.11",
|
||||||
"v8-compile-cache": "^2.3.0",
|
"v8-compile-cache": "^2.3.0",
|
||||||
"wallpaper": "5.0.1",
|
"wallpaper": "5.0.1",
|
||||||
"ws": "^8.5.0",
|
"ws": "^8.5.0",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen } from "electron";
|
import { app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen, dialog } from "electron";
|
||||||
import * as windowStateKeeper from "electron-window-state";
|
import * as windowStateKeeper from "electron-window-state";
|
||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
import * as getPort from "get-port";
|
import * as getPort from "get-port";
|
||||||
|
@ -27,8 +27,7 @@ import { watch } from "chokidar";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import wallpaper from "wallpaper";
|
import wallpaper from "wallpaper";
|
||||||
import * as AdmZip from "adm-zip";
|
import * as AdmZip from "adm-zip";
|
||||||
import * as path from 'path';
|
import { LocalFiles } from "../providers/local/";
|
||||||
const { readdir } = require('fs').promises;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,11 +39,11 @@ const { readdir } = require('fs').promises;
|
||||||
export class BrowserWindow {
|
export class BrowserWindow {
|
||||||
public static win: any | undefined = null;
|
public static win: any | undefined = null;
|
||||||
private devMode: boolean = !app.isPackaged;
|
private devMode: boolean = !app.isPackaged;
|
||||||
|
public static express: any | undefined = null;
|
||||||
|
|
||||||
private audioStream: any = new Stream.PassThrough();
|
private audioStream: any = new Stream.PassThrough();
|
||||||
private headerSent: any = false;
|
private headerSent: any = false;
|
||||||
private chromecastIP: any = [];
|
private chromecastIP: any = [];
|
||||||
private localSongs: any = [];
|
|
||||||
private clientPort: number = 0;
|
private clientPort: number = 0;
|
||||||
private remotePort: number = 6942;
|
private remotePort: number = 6942;
|
||||||
private EnvironmentVariables: object = {
|
private EnvironmentVariables: object = {
|
||||||
|
@ -121,6 +120,7 @@ export class BrowserWindow {
|
||||||
"components/fullscreen",
|
"components/fullscreen",
|
||||||
"components/miniplayer",
|
"components/miniplayer",
|
||||||
"components/castmenu",
|
"components/castmenu",
|
||||||
|
"components/pathmenu",
|
||||||
"components/airplay-modal",
|
"components/airplay-modal",
|
||||||
"components/artist-chip",
|
"components/artist-chip",
|
||||||
"components/hello-world",
|
"components/hello-world",
|
||||||
|
@ -408,9 +408,10 @@ export class BrowserWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the webserver for the browser window to load
|
// Start the webserver for the browser window to load
|
||||||
|
// LocalFiles.DB.init()
|
||||||
this.startWebServer();
|
this.startWebServer();
|
||||||
|
|
||||||
|
|
||||||
BrowserWindow.win = new bw(this.options);
|
BrowserWindow.win = new bw(this.options);
|
||||||
// cant be built in CI
|
// cant be built in CI
|
||||||
// if (process.platform === "win32" && (utils.getStoreValue('visual.transparent') ?? false)) {
|
// if (process.platform === "win32" && (utils.getStoreValue('visual.transparent') ?? false)) {
|
||||||
|
@ -466,7 +467,7 @@ export class BrowserWindow {
|
||||||
*/
|
*/
|
||||||
private startWebServer(): void {
|
private startWebServer(): void {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
BrowserWindow.express = app;
|
||||||
app.use(express.static(join(utils.getPath('srcPath'), "./renderer/")));
|
app.use(express.static(join(utils.getPath('srcPath'), "./renderer/")));
|
||||||
app.set("views", join(utils.getPath('srcPath'), "./renderer/views"));
|
app.set("views", join(utils.getPath('srcPath'), "./renderer/views"));
|
||||||
app.set("view engine", "ejs");
|
app.set("view engine", "ejs");
|
||||||
|
@ -550,16 +551,6 @@ export class BrowserWindow {
|
||||||
res.send(`// Theme not found - ${userThemePath}`);
|
res.send(`// Theme not found - ${userThemePath}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
app.get("/ciderlocal/:songs", (req, res) => {
|
|
||||||
const audio = atob(req.params.songs.replace(/_/g, '/').replace(/-/g, '+'));
|
|
||||||
console.log('auss', audio)
|
|
||||||
let data = {
|
|
||||||
data:
|
|
||||||
this.localSongs.filter((f: any) => audio.split(',').includes(f.id))
|
|
||||||
};
|
|
||||||
res.send(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
app.get("/themes/:theme/*", (req: { params: { theme: string, 0: string } }, res) => {
|
app.get("/themes/:theme/*", (req: { params: { theme: string, 0: string } }, res) => {
|
||||||
const theme = req.params.theme;
|
const theme = req.params.theme;
|
||||||
|
@ -623,6 +614,9 @@ export class BrowserWindow {
|
||||||
utils.getWindow().webContents.send('setStoreValue', 'connectUser', JSON.parse(req.params.data))
|
utils.getWindow().webContents.send('setStoreValue', 'connectUser', JSON.parse(req.params.data))
|
||||||
res.redirect(`https://connect.cidercollective.dev/linked.html`)
|
res.redirect(`https://connect.cidercollective.dev/linked.html`)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
LocalFiles.setupHandlers()
|
||||||
|
|
||||||
// [Connect] Set auth URL in store for `shell.openExternal`
|
// [Connect] Set auth URL in store for `shell.openExternal`
|
||||||
utils.setStoreValue('cc_authURL', `https://connect.cidercollective.dev/callback/discord?app=cider&appPort=${this.clientPort}`)
|
utils.setStoreValue('cc_authURL', `https://connect.cidercollective.dev/callback/discord?app=cider&appPort=${this.clientPort}`)
|
||||||
console.log(`[Connect] Auth URL: ${utils.getStoreValue('cc_authURL')}`)
|
console.log(`[Connect] Auth URL: ${utils.getStoreValue('cc_authURL')}`)
|
||||||
|
@ -673,9 +667,9 @@ export class BrowserWindow {
|
||||||
callback({
|
callback({
|
||||||
redirectURL: `http://localhost:${this.clientPort}/apple-hls.js`,
|
redirectURL: `http://localhost:${this.clientPort}/apple-hls.js`,
|
||||||
});
|
});
|
||||||
} else if (details.url.includes("ciderlocal")) {
|
} else if (details.url.includes("ciderlocal") && !details.url.includes("https://apic-desktop.musixmatch.com") ) {
|
||||||
let text = details.url.toString().includes('ids=') ? decodeURIComponent(details.url.toString()).split("?ids=")[1] : decodeURIComponent(details.url.toString().substring(details.url.toString().lastIndexOf('/') + 1));
|
let text = details.url.toString().includes('ids=') ? decodeURIComponent(details.url.toString()).split("?ids=")[1] : decodeURIComponent(details.url.toString().substring(details.url.toString().lastIndexOf('/') + 1));
|
||||||
console.log('localurl', text)
|
//console.log('localurl',text)
|
||||||
callback({
|
callback({
|
||||||
redirectURL: `http://localhost:${this.clientPort}/ciderlocal/${Buffer.from(text).toString('base64url')}`,
|
redirectURL: `http://localhost:${this.clientPort}/ciderlocal/${Buffer.from(text).toString('base64url')}`,
|
||||||
});
|
});
|
||||||
|
@ -1190,103 +1184,13 @@ export class BrowserWindow {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
ipcMain.on("scanLibrary", async (event, folders) => {
|
ipcMain.handle("scanLibrary", async (event, folders) => {
|
||||||
async function getFiles(dir: any) {
|
const oldmetadatalist = await LocalFiles.sendOldLibrary()
|
||||||
const dirents = await readdir(dir, { withFileTypes: true });
|
BrowserWindow.win.webContents.send('getUpdatedLocalList', oldmetadatalist);
|
||||||
const files = await Promise.all(dirents.map((dirent: any) => {
|
const metadatalist = await LocalFiles.scanLibrary()
|
||||||
const res = path.resolve(dir, dirent.name);
|
|
||||||
return dirent.isDirectory() ? getFiles(res) : res;
|
|
||||||
}));
|
|
||||||
return Array.prototype.concat(...files);
|
|
||||||
}
|
|
||||||
if (folders == null || folders.length == null || folders.length == 0) folders = ["D:\\Music"]
|
|
||||||
console.log('folders', folders)
|
|
||||||
let files: any[] = []
|
|
||||||
for (var folder of folders) {
|
|
||||||
// get files from the Music folder
|
|
||||||
files = files.concat(await getFiles(folder))
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log("cider.files", files2);
|
|
||||||
let supporttedformats = ["mp3", "aac", "webm", "flac", "m4a", "ogg", "wav", "opus"]
|
|
||||||
let audiofiles = files.filter(f => supporttedformats.includes(f.substring(f.lastIndexOf('.') + 1)));
|
|
||||||
// console.log("cider.files2", audiofiles, audiofiles.length);
|
|
||||||
let metadatalist = []
|
|
||||||
let numid = 0;
|
|
||||||
for (var audio of audiofiles) {
|
|
||||||
try {
|
|
||||||
const metadata = await mm.parseFile(audio);
|
|
||||||
if (metadata != null) {
|
|
||||||
let form = {
|
|
||||||
"id": "ciderlocal" + numid,
|
|
||||||
"type": "podcast-episodes",
|
|
||||||
"href": audio,
|
|
||||||
"attributes": {
|
|
||||||
"artwork": {
|
|
||||||
"width": 3000,
|
|
||||||
"height": 3000,
|
|
||||||
"url": metadata.common.picture != undefined ? "data:image/png;base64," + metadata.common.picture[0].data.toString('base64') + "" : "",
|
|
||||||
},
|
|
||||||
"topics": [],
|
|
||||||
"url": "",
|
|
||||||
"subscribable": true,
|
|
||||||
"mediaKind": "audio",
|
|
||||||
"genreNames": [
|
|
||||||
""
|
|
||||||
],
|
|
||||||
// "playParams": {
|
|
||||||
// "id": "ciderlocal" + numid,
|
|
||||||
// "kind": "podcast",
|
|
||||||
// "isLibrary": true,
|
|
||||||
// "reporting": false },
|
|
||||||
"trackNumber": metadata.common.track?.no ?? 0,
|
|
||||||
"discNumber": metadata.common.disk?.no ?? 0,
|
|
||||||
"name": metadata.common.title ?? audio.substring(audio.lastIndexOf('\\') + 1),
|
|
||||||
"albumName": metadata.common.album,
|
|
||||||
"artistName": metadata.common.artist,
|
|
||||||
"copyright": metadata.common.copyright ?? "",
|
|
||||||
"assetUrl": "file:///" + audio,
|
|
||||||
"contentAdvisory": "",
|
|
||||||
"releaseDateTime": "2022-05-13T00:23:00Z",
|
|
||||||
"durationInMilliseconds": Math.floor((metadata.format.duration ?? 0) * 1000),
|
|
||||||
|
|
||||||
"offers": [
|
|
||||||
{
|
|
||||||
"kind": "get",
|
|
||||||
"type": "STDQ"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"contentRating": "clean"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
numid += 1;
|
|
||||||
|
|
||||||
// let form = {"id": "/ciderlocal?" + audio,
|
|
||||||
// "type": "library-songs",
|
|
||||||
// "href": "/ciderlocal?" + audio,
|
|
||||||
// "artwork": {
|
|
||||||
// "url": metadata.common.picture != undefined ? "data:image/png;base64,"+metadata.common.picture[0].data.toString('base64')+"" : "",
|
|
||||||
// },
|
|
||||||
// "attributes":
|
|
||||||
// { "durationInMillis": Math.floor((metadata.format.duration?? 0) * 1000),
|
|
||||||
// "hasLyrics": false,
|
|
||||||
// "playParams": { "id": "/ciderlocal?" + audio, "kind": "song", "isLibrary": true, "reporting": false },
|
|
||||||
// "trackNumber": 0,
|
|
||||||
// "discNumber": 0,
|
|
||||||
// "genreNames": [""],
|
|
||||||
// "name": metadata.common.title,
|
|
||||||
// "albumName": metadata.common.album,
|
|
||||||
// "artistName": metadata.common.artist}}
|
|
||||||
metadatalist.push(form)
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
}
|
|
||||||
// console.log('metadatalist', metadatalist);
|
|
||||||
this.localSongs = metadatalist;
|
|
||||||
BrowserWindow.win.webContents.send('getUpdatedLocalList', metadatalist);
|
BrowserWindow.win.webContents.send('getUpdatedLocalList', metadatalist);
|
||||||
}
|
LocalFiles.cleanUpDB()
|
||||||
|
})
|
||||||
)
|
|
||||||
|
|
||||||
ipcMain.on('writeWAV', (event, leftpcm, rightpcm, bufferlength) => {
|
ipcMain.on('writeWAV', (event, leftpcm, rightpcm, bufferlength) => {
|
||||||
|
|
||||||
|
@ -1479,10 +1383,17 @@ export class BrowserWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('open-appdata', (_event) => {
|
ipcMain.on('open-appdata', (_event) => {
|
||||||
shell.openPath(app.getPath('userData'));
|
shell.openPath(app.getPath('userData'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('folderSelector', async (_event) => {
|
||||||
|
let u = await dialog.showOpenDialog({
|
||||||
|
properties: ['openDirectory', 'multiSelections']
|
||||||
|
});
|
||||||
|
return u.filePaths
|
||||||
|
});
|
||||||
|
|
||||||
//#region Cider Connect
|
//#region Cider Connect
|
||||||
ipcMain.on('cc-auth', (_event) => {
|
ipcMain.on('cc-auth', (_event) => {
|
||||||
|
|
|
@ -31,7 +31,8 @@ export class Store {
|
||||||
"applemusic": false,
|
"applemusic": false,
|
||||||
"library": false,
|
"library": false,
|
||||||
"amplaylists": false,
|
"amplaylists": false,
|
||||||
"playlists": false
|
"playlists": false,
|
||||||
|
"localLibrary": false
|
||||||
},
|
},
|
||||||
"onStartup": {
|
"onStartup": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
@ -155,6 +156,7 @@ export class Store {
|
||||||
"sortOrder": "asc",
|
"sortOrder": "asc",
|
||||||
"viewAs": "covers"
|
"viewAs": "covers"
|
||||||
},
|
},
|
||||||
|
"localPaths": []
|
||||||
},
|
},
|
||||||
"audio": {
|
"audio": {
|
||||||
"volume": 1,
|
"volume": 1,
|
||||||
|
|
|
@ -68,6 +68,14 @@ export class utils {
|
||||||
return ipcMain
|
return ipcMain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the Express instance
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
static getExpress(): any {
|
||||||
|
return bw.express
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the i18n locale for the given language.
|
* Fetches the i18n locale for the given language.
|
||||||
* @param language {string} The language to fetch the locale for.
|
* @param language {string} The language to fetch the locale for.
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
"components/fullscreen",
|
"components/fullscreen",
|
||||||
"components/miniplayer",
|
"components/miniplayer",
|
||||||
"components/castmenu",
|
"components/castmenu",
|
||||||
|
"components/pathmenu",
|
||||||
"components/airplay-modal",
|
"components/airplay-modal",
|
||||||
"components/artist-chip",
|
"components/artist-chip",
|
||||||
"components/hello-world",
|
"components/hello-world",
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {init as Sentry} from "@sentry/electron";
|
||||||
import {RewriteFrames} from "@sentry/integrations";
|
import {RewriteFrames} from "@sentry/integrations";
|
||||||
import {components, ipcMain} from "electron"
|
import {components, ipcMain} from "electron"
|
||||||
|
|
||||||
|
|
||||||
// Analytics for debugging fun yeah.
|
// Analytics for debugging fun yeah.
|
||||||
Sentry({
|
Sentry({
|
||||||
dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214",
|
dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214",
|
||||||
|
|
12
src/main/providers/local/db/index.ts
Normal file
12
src/main/providers/local/db/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import * as PouchDB from 'pouchdb-node';
|
||||||
|
import {join} from 'path';
|
||||||
|
import {app} from "electron";
|
||||||
|
PouchDB.plugin(require('pouchdb-upsert'));
|
||||||
|
export class ProviderDB {
|
||||||
|
public static db: any = null
|
||||||
|
static init() {
|
||||||
|
if (ProviderDB.db == null){
|
||||||
|
ProviderDB.db = new PouchDB(join(app.getPath('userData'), 'tracksdb'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
172
src/main/providers/local/index.ts
Normal file
172
src/main/providers/local/index.ts
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
import { ProviderDB } from "./db";
|
||||||
|
import * as path from 'path';
|
||||||
|
const { readdir } = require('fs').promises;
|
||||||
|
import { utils } from '../../base/utils';
|
||||||
|
import * as mm from 'music-metadata';
|
||||||
|
import {Md5} from 'ts-md5/dist/md5';
|
||||||
|
import e from "express";
|
||||||
|
|
||||||
|
export class LocalFiles {
|
||||||
|
static localSongs: any = [];
|
||||||
|
static localSongsArts: any = [];
|
||||||
|
public static DB = ProviderDB.db;
|
||||||
|
|
||||||
|
static getDataType(item_id : String | any){
|
||||||
|
if ((item_id ?? ('')).startsWith('ciderlocalart'))
|
||||||
|
return 'artwork'
|
||||||
|
else if ((item_id ?? ('')).startsWith('ciderlocal'))
|
||||||
|
return 'track'
|
||||||
|
}
|
||||||
|
|
||||||
|
static async sendOldLibrary() {
|
||||||
|
ProviderDB.init()
|
||||||
|
let rows = (await ProviderDB.db.allDocs({include_docs: true,
|
||||||
|
attachments: true})).rows.map((item: any)=>{return item.doc})
|
||||||
|
let tracks = rows.filter((item: any) => {return this.getDataType(item._id) == "track"})
|
||||||
|
let arts = rows.filter((item: any) => {return this.getDataType(item._id) == "artwork"})
|
||||||
|
this.localSongs = tracks;
|
||||||
|
this.localSongsArts = arts;
|
||||||
|
return tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async scanLibrary() {
|
||||||
|
ProviderDB.init()
|
||||||
|
let folders = utils.getStoreValue("libraryPrefs.localPaths")
|
||||||
|
if (folders == null || folders.length == null || folders.length == 0) folders = []
|
||||||
|
console.log('folders', folders)
|
||||||
|
let files: any[] = []
|
||||||
|
for (var folder of folders) {
|
||||||
|
// get files from the Music folder
|
||||||
|
files = files.concat(await LocalFiles.getFiles(folder))
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("cider.files", files2);
|
||||||
|
let supporttedformats = ["mp3", "aac", "webm", "flac", "m4a", "ogg", "wav", "opus"]
|
||||||
|
let audiofiles = files.filter(f => supporttedformats.includes(f.substring(f.lastIndexOf('.') + 1)));
|
||||||
|
// console.log("cider.files2", audiofiles, audiofiles.length);
|
||||||
|
let metadatalist = []
|
||||||
|
let metadatalistart = []
|
||||||
|
let numid = 0;
|
||||||
|
for (var audio of audiofiles) {
|
||||||
|
try {
|
||||||
|
const metadata = await mm.parseFile(audio);
|
||||||
|
let lochash = Md5.hashStr(audio) ?? numid;
|
||||||
|
if (metadata != null) {
|
||||||
|
let form = {
|
||||||
|
"id": "ciderlocal" + lochash,
|
||||||
|
"_id": "ciderlocal" + lochash,
|
||||||
|
"type": "podcast-episodes",
|
||||||
|
"href": audio,
|
||||||
|
"attributes": {
|
||||||
|
"artwork": {
|
||||||
|
"width": 3000,
|
||||||
|
"height": 3000,
|
||||||
|
"url": "/ciderlocalart/" + "ciderlocal" + lochash,
|
||||||
|
},
|
||||||
|
"topics": [],
|
||||||
|
"url": "",
|
||||||
|
"subscribable": true,
|
||||||
|
"mediaKind": "audio",
|
||||||
|
"genreNames": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
// "playParams": {
|
||||||
|
// "id": "ciderlocal" + numid,
|
||||||
|
// "kind": "podcast",
|
||||||
|
// "isLibrary": true,
|
||||||
|
// "reporting": false },
|
||||||
|
"trackNumber": metadata.common.track?.no ?? 0,
|
||||||
|
"discNumber": metadata.common.disk?.no ?? 0,
|
||||||
|
"name": metadata.common.title ?? audio.substring(audio.lastIndexOf('\\') + 1),
|
||||||
|
"albumName": metadata.common.album,
|
||||||
|
"artistName": metadata.common.artist,
|
||||||
|
"copyright": metadata.common.copyright ?? "",
|
||||||
|
"assetUrl": "file:///" + audio,
|
||||||
|
"contentAdvisory": "",
|
||||||
|
"releaseDateTime": `${metadata?.common?.year ?? '2022'}-05-13T00:23:00Z`,
|
||||||
|
"durationInMillis": Math.floor((metadata.format.duration ?? 0) * 1000),
|
||||||
|
|
||||||
|
"offers": [
|
||||||
|
{
|
||||||
|
"kind": "get",
|
||||||
|
"type": "STDQ"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contentRating": "clean"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let art = {
|
||||||
|
id: "ciderlocal" + lochash,
|
||||||
|
_id: "ciderlocalart" + lochash,
|
||||||
|
url: metadata.common.picture != undefined ? metadata.common.picture[0].data.toString('base64') : "",
|
||||||
|
}
|
||||||
|
metadatalistart.push(art)
|
||||||
|
numid += 1;
|
||||||
|
ProviderDB.db.putIfNotExists(form)
|
||||||
|
ProviderDB.db.putIfNotExists(art)
|
||||||
|
metadatalist.push(form)
|
||||||
|
}
|
||||||
|
//delete removed tracks
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
this.localSongs = metadatalist;
|
||||||
|
this.localSongsArts = metadatalistart;
|
||||||
|
return metadatalist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async cleanUpDB(){
|
||||||
|
let folders = utils.getStoreValue("libraryPrefs.localPaths")
|
||||||
|
let rows = (await ProviderDB.db.allDocs({include_docs: true,
|
||||||
|
attachments: true})).rows.map((item: any)=>{return item.doc})
|
||||||
|
let tracks = rows.filter((item: any) => {return this.getDataType(item._id) == "track" && !folders.some((i: String) => {return item["attributes"]["assetUrl"].startsWith("file:///" + i)})})
|
||||||
|
let hashs = tracks.map((i: any) => {return i._id})
|
||||||
|
for (let hash of hashs){
|
||||||
|
try{
|
||||||
|
ProviderDB.db.get(hash).then(function (doc: any) {
|
||||||
|
return ProviderDB.db.remove(doc);
|
||||||
|
});} catch(e){}
|
||||||
|
try{
|
||||||
|
ProviderDB.db.get(hash.replace('ciderlocal','ciderlocalart')).then(function (doc: any) {
|
||||||
|
return ProviderDB.db.remove(doc);
|
||||||
|
});} catch(e){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getFiles(dir: any) {
|
||||||
|
const dirents = await readdir(dir, { withFileTypes: true });
|
||||||
|
const files = await Promise.all(dirents.map((dirent: any) => {
|
||||||
|
const res = path.resolve(dir, dirent.name);
|
||||||
|
return dirent.isDirectory() ? this.getFiles(res) : res;
|
||||||
|
}));
|
||||||
|
return Array.prototype.concat(...files);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setupHandlers () {
|
||||||
|
const app = utils.getExpress()
|
||||||
|
console.log("Setting up handlers for local files")
|
||||||
|
app.get("/ciderlocal/:songs", (req: any, res: any) => {
|
||||||
|
const audio = atob(req.params.songs.replace(/_/g, '/').replace(/-/g, '+'));
|
||||||
|
//console.log('auss', audio)
|
||||||
|
let data = {
|
||||||
|
data:
|
||||||
|
LocalFiles.localSongs.filter((f: any) => audio.split(',').includes(f.id))
|
||||||
|
};
|
||||||
|
res.send(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/ciderlocalart/:songs", (req: any, res: any) => {
|
||||||
|
const audio = req.params.songs;
|
||||||
|
// metadata.common.picture[0].data.toString('base64')
|
||||||
|
|
||||||
|
res.setHeader('Cache-Control', 'public, max-age=31536000');
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 31536000).toUTCString());
|
||||||
|
res.setHeader('Content-Type', 'image/jpeg');
|
||||||
|
|
||||||
|
let data =
|
||||||
|
LocalFiles.localSongsArts.filter((f: any) => f.id == audio);
|
||||||
|
res.status(200).send(Buffer.from(data[0]?.url, 'base64'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
}
|
|
@ -386,7 +386,7 @@ const CiderAudio = {
|
||||||
if (this._isBufferFull()) {
|
if (this._isBufferFull()) {
|
||||||
this._flush();
|
this._flush();
|
||||||
}
|
}
|
||||||
let dataLength = audioRawData[0].length;
|
let dataLength = audioRawData[0]?.length ?? 0;
|
||||||
for (let idx=0; idx<dataLength; idx++) {
|
for (let idx=0; idx<dataLength; idx++) {
|
||||||
for (let channel=0; channel < numberOfChannels; channel++) {
|
for (let channel=0; channel < numberOfChannels; channel++) {
|
||||||
let value = audioRawData[channel][idx];
|
let value = audioRawData[channel][idx];
|
||||||
|
@ -467,7 +467,7 @@ const CiderAudio = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CiderAudio.audioNodes.recorderNode.parameters.get('isRecording').setValueAtTime(1, CiderAudio.context.currentTime);
|
CiderAudio.audioNodes.recorderNode.parameters.get('isRecording').setValueAtTime(1, CiderAudio.context.currentTime);
|
||||||
CiderAudio.audioNodes.gainNode.connect(CiderAudio.audioNodes.recorderNode);
|
CiderAudio.audioNodes.intelliGainComp.connect(CiderAudio.audioNodes.recorderNode);
|
||||||
|
|
||||||
});
|
});
|
||||||
clearInterval(searchInt);
|
clearInterval(searchInt);
|
||||||
|
|
|
@ -216,6 +216,7 @@ const app = new Vue({
|
||||||
audioPlaybackRate: false,
|
audioPlaybackRate: false,
|
||||||
showPlaylist: false,
|
showPlaylist: false,
|
||||||
castMenu: false,
|
castMenu: false,
|
||||||
|
pathMenu: false,
|
||||||
moreInfo: false,
|
moreInfo: false,
|
||||||
airplayPW: false,
|
airplayPW: false,
|
||||||
settings: false
|
settings: false
|
||||||
|
@ -858,7 +859,7 @@ const app = new Vue({
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcRenderer.on('getUpdatedLocalList', (event, data) => {
|
ipcRenderer.on('getUpdatedLocalList', (event, data) => {
|
||||||
console.log("cider-local", data);
|
// console.log("cider-local", data);
|
||||||
this.library.localsongs = data;
|
this.library.localsongs = data;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1072,6 +1073,8 @@ const app = new Vue({
|
||||||
if (this.cfg.general.themeUpdateNotification && !this.isDev) {
|
if (this.cfg.general.themeUpdateNotification && !this.isDev) {
|
||||||
this.checkForThemeUpdates()
|
this.checkForThemeUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipcRenderer.invoke("scanLibrary")
|
||||||
},
|
},
|
||||||
showFoo(querySelector, time) {
|
showFoo(querySelector, time) {
|
||||||
clearTimeout(this.idleTimer);
|
clearTimeout(this.idleTimer);
|
||||||
|
@ -1912,7 +1915,7 @@ const app = new Vue({
|
||||||
this.routeView(item.relationships.contents.data[0])
|
this.routeView(item.relationships.contents.data[0])
|
||||||
} else if (item.attributes?.link?.url != null) {
|
} else if (item.attributes?.link?.url != null) {
|
||||||
if (item.attributes.link.url.includes("viewMultiRoom")) {
|
if (item.attributes.link.url.includes("viewMultiRoom")) {
|
||||||
const params = new Proxy(new URLSearchParams(item.attributes.link.url), {
|
const params = new Proxy(new URLSearchParams(new URL(item.attributes.link.url).search), {
|
||||||
get: (searchParams, prop) => searchParams.get(prop),
|
get: (searchParams, prop) => searchParams.get(prop),
|
||||||
});
|
});
|
||||||
id = params.fcId
|
id = params.fcId
|
||||||
|
@ -3500,7 +3503,15 @@ const app = new Vue({
|
||||||
console.log(truekind, id)
|
console.log(truekind, id)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (app.library.songs.displayListing.length > childIndex && parent == "librarysongs") {
|
if (parent == 'playlist:ciderlocal'){
|
||||||
|
let u = app.library.localsongs.map(i => {return i.id})
|
||||||
|
app.mk.setQueue({"episodes" : u}).then(()=>{
|
||||||
|
let id = app.mk.queue._itemIDs.findIndex(element => element == item.id);
|
||||||
|
app.mk.changeToMediaAtIndex(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (app.library.songs.displayListing.length > childIndex && parent == "librarysongs") {
|
||||||
console.log(item)
|
console.log(item)
|
||||||
if (item && ((app.library.songs.displayListing[childIndex].id != item.id))) {
|
if (item && ((app.library.songs.displayListing[childIndex].id != item.id))) {
|
||||||
childIndex = app.library.songs.displayListing.indexOf(item)
|
childIndex = app.library.songs.displayListing.indexOf(item)
|
||||||
|
@ -3804,7 +3815,7 @@ const app = new Vue({
|
||||||
type += "s"
|
type += "s"
|
||||||
}
|
}
|
||||||
type = type.replace("library-", "")
|
type = type.replace("library-", "")
|
||||||
let id = item.attributes.playParams.catalogId ?? item.attributes.playParams.id ?? item.id
|
let id = item.attributes.playParams?.catalogId ?? item.attributes.playParams.id ?? item.id
|
||||||
|
|
||||||
let index = types.findIndex(function (type) {
|
let index = types.findIndex(function (type) {
|
||||||
return type.type == this
|
return type.type == this
|
||||||
|
|
|
@ -16458,7 +16458,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
--chromeHeight1: 60px;
|
--chromeHeight1: 70px;
|
||||||
}
|
}
|
||||||
.fullscreen-view .app-content-container {
|
.fullscreen-view .app-content-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -16484,8 +16484,6 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: var(--chromeHeight1);
|
height: var(--chromeHeight1);
|
||||||
background: var(--color1);
|
|
||||||
backdrop-filter: var(--glassFilter);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -16496,8 +16494,9 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
border: 1px solid #323232;
|
border: 1px solid #323232;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 42px;
|
height: 55px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
backdrop-filter: var(--glassFilter);
|
||||||
}
|
}
|
||||||
.fullscreen-view .fs-header .top-nav-group .app-sidebar-item {
|
.fullscreen-view .fs-header .top-nav-group .app-sidebar-item {
|
||||||
background-color: #1e1e1e00;
|
background-color: #1e1e1e00;
|
||||||
|
@ -16510,6 +16509,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
.fullscreen-view .fs-header .top-nav-group .app-sidebar-item:before {
|
.fullscreen-view .fs-header .top-nav-group .app-sidebar-item:before {
|
||||||
--dist: 1px;
|
--dist: 1px;
|
||||||
|
@ -16850,10 +16851,25 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
font-weight: 380;
|
font-weight: 380;
|
||||||
}
|
}
|
||||||
|
.fullscreen-view .cd-mediaitem-list-item .duration {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
.fullscreen-view .cd-mediaitem-list-item .artwork {
|
.fullscreen-view .cd-mediaitem-list-item .artwork {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
|
.fullscreen-view .cd-btn-seeall {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
.fullscreen-view h1 {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
.fullscreen-view h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.fullscreen-view .home-page .well.artistfeed-well {
|
||||||
|
height: 512px;
|
||||||
|
}
|
||||||
.fullscreen-view .header-text {
|
.fullscreen-view .header-text {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
@ -16891,6 +16907,20 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
|
.fullscreen-view .playlist-page .playlist-display .playlistInfo .playlist-hero {
|
||||||
|
transform: unset;
|
||||||
|
}
|
||||||
|
.fullscreen-view .artist-page .artist-header {
|
||||||
|
min-height: 60vh;
|
||||||
|
}
|
||||||
|
.fullscreen-view .artist-page .artist-image {
|
||||||
|
width: 20vh;
|
||||||
|
height: 20vh;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
.fullscreen-view .artist-page.animated .artist-header {
|
||||||
|
min-height: 80vh;
|
||||||
|
}
|
||||||
.fullscreen-view .playlist-page .playlist-body {
|
.fullscreen-view .playlist-page .playlist-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<castmenu v-if="modals.castMenu"></castmenu>
|
<castmenu v-if="modals.castMenu"></castmenu>
|
||||||
</transition>
|
</transition>
|
||||||
|
<transition name="modal">
|
||||||
|
<pathmenu v-if="modals.pathMenu"></pathmenu>
|
||||||
|
</transition>
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<airplay-modal v-if="modals.airplayPW"></airplay-modal>
|
<airplay-modal v-if="modals.airplayPW"></airplay-modal>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
|
@ -137,8 +137,8 @@
|
||||||
v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
|
v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col right-col" v-if="tabMode != ''">
|
<div class="col right-col" v-if="tabMode != ''">
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
@controller-click="route()"
|
@controller-click="route()"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
|
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
|
||||||
<div v-show="isVisible" class="listitem-content">
|
<div v-if="isVisible" class="listitem-content">
|
||||||
<div class="popular" v-if="!showInLibrary && item?.meta?.popularity != null && item?.meta?.popularity > 0.7"></div>
|
<div class="popular" v-if="!showInLibrary && item?.meta?.popularity != null && item?.meta?.popularity > 0.7"></div>
|
||||||
<div class="isLibrary" v-if="showLibraryStatus == true">
|
<div class="isLibrary" v-if="showLibraryStatus == true">
|
||||||
<div v-if="showInLibrary" :style="{display: (showInLibrary ? 'block' : 'none'), 'margin-left':'11px'}">
|
<div v-if="showInLibrary" :style="{display: (showInLibrary ? 'block' : 'none'), 'margin-left':'11px'}">
|
||||||
|
@ -123,8 +123,8 @@
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.item.attributes.playParams) {
|
if (this.item.attributes.playParams) {
|
||||||
this.itemId = this.item.attributes.playParams.id ?? this.item.id;
|
this.itemId = this.item.attributes.playParams?.id ?? this.item.id;
|
||||||
this.isLibrary = this.item.attributes.playParams.isLibrary ?? false;
|
this.isLibrary = this.item.attributes.playParams?.isLibrary ?? false;
|
||||||
} else {
|
} else {
|
||||||
this.itemId = this.item.id;
|
this.itemId = this.item.id;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,9 @@
|
||||||
return color
|
return color
|
||||||
},
|
},
|
||||||
async checkLibrary() {
|
async checkLibrary() {
|
||||||
|
if (this.item.id.startsWith('ciderlocal')){
|
||||||
|
return true
|
||||||
|
}
|
||||||
if (this.addedToLibrary) { return this.addedToLibrary }
|
if (this.addedToLibrary) { return this.addedToLibrary }
|
||||||
if (this.item.type.includes("library-playlists") || this.item.type.includes("station")) {
|
if (this.item.type.includes("library-playlists") || this.item.type.includes("station")) {
|
||||||
this.addedToLibrary = true
|
this.addedToLibrary = true
|
||||||
|
@ -155,7 +158,7 @@
|
||||||
},
|
},
|
||||||
getClasses() {
|
getClasses() {
|
||||||
this.addClasses = {}
|
this.addClasses = {}
|
||||||
if (typeof this.item.attributes.playParams == "undefined") {
|
if (typeof this.item.attributes.playParams == "undefined" && this.item.type != "podcast-episodes") {
|
||||||
this.addClasses["disabled"] = true
|
this.addClasses["disabled"] = true
|
||||||
}
|
}
|
||||||
if (this.classList) {
|
if (this.classList) {
|
||||||
|
@ -167,7 +170,7 @@
|
||||||
},
|
},
|
||||||
dragStart(evt) {
|
dragStart(evt) {
|
||||||
evt.dataTransfer.setData('text/plain', JSON.stringify({
|
evt.dataTransfer.setData('text/plain', JSON.stringify({
|
||||||
type: this.item.attributes.playParams.kind ?? this.item.type,
|
type: this.item.attributes.playParams?.kind ?? this.item.type,
|
||||||
id: this.item.id
|
id: this.item.id
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -182,20 +185,23 @@
|
||||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||||
},
|
},
|
||||||
getDataType() {
|
getDataType() {
|
||||||
|
let type = ''
|
||||||
if (typeof this.item.attributes.playParams != "undefined") {
|
if (typeof this.item.attributes.playParams != "undefined") {
|
||||||
if (this.item.attributes.playParams.isLibrary) {
|
if (this.item.attributes.playParams?.isLibrary) {
|
||||||
return this.item.type
|
type = this.item.type
|
||||||
} else {
|
} else {
|
||||||
return this.item.attributes.playParams.kind
|
type = this.item.attributes.playParams?.kind
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return this.item.type
|
type = this.item.type
|
||||||
}
|
}
|
||||||
|
if (type == 'podcast-episodes') type = 'episode';
|
||||||
|
return type;
|
||||||
},
|
},
|
||||||
select(e) {
|
select(e) {
|
||||||
let data_type = this.getDataType()
|
let data_type = this.getDataType()
|
||||||
let item_id = this.item.attributes.playParams.id ?? this.item.id
|
let item_id = this.item.attributes.playParams?.id ?? this.item.id
|
||||||
let isLibrary = this.item.attributes.playParams.isLibrary ?? false
|
let isLibrary = this.item.attributes.playParams?.isLibrary ?? false
|
||||||
|
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
if (this.index != -1) {
|
if (this.index != -1) {
|
||||||
|
@ -259,8 +265,8 @@
|
||||||
async contextMenu(event) {
|
async contextMenu(event) {
|
||||||
let self = this
|
let self = this
|
||||||
let data_type = this.getDataType()
|
let data_type = this.getDataType()
|
||||||
let item_id = this.item.attributes.playParams.id ?? this.item.id
|
let item_id = this.item.attributes.playParams?.id ?? this.item.id
|
||||||
let isLibrary = this.item.attributes.playParams.isLibrary ?? false
|
let isLibrary = this.item.attributes.playParams?.isLibrary ?? false
|
||||||
|
|
||||||
let useMenu = "normal"
|
let useMenu = "normal"
|
||||||
if (app.selectedMediaItems.length <= 1) {
|
if (app.selectedMediaItems.length <= 1) {
|
||||||
|
@ -319,6 +325,7 @@
|
||||||
app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] })
|
app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(itemsToPlay)
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -400,7 +407,9 @@
|
||||||
"name": app.getLz('action.playNext'),
|
"name": app.getLz('action.playNext'),
|
||||||
"icon": "./assets/arrow-bend-up.svg",
|
"icon": "./assets/arrow-bend-up.svg",
|
||||||
"action": function () {
|
"action": function () {
|
||||||
app.mk.playNext({ [self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id })
|
let type = self.item.attributes.playParams?.kind ?? self.item.type
|
||||||
|
if (type == "podcast-episodes") {type = "episode"}
|
||||||
|
app.mk.playNext({ [type]: self.item.attributes.playParams?.id ?? self.item.id })
|
||||||
app.mk.queue._reindex()
|
app.mk.queue._reindex()
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
}
|
}
|
||||||
|
@ -409,7 +418,9 @@
|
||||||
"name": app.getLz('action.playLater'),
|
"name": app.getLz('action.playLater'),
|
||||||
"icon": "./assets/arrow-bend-down.svg",
|
"icon": "./assets/arrow-bend-down.svg",
|
||||||
"action": function () {
|
"action": function () {
|
||||||
app.mk.playLater({ [self.item.attributes.playParams.kind ?? self.item.type]: self.item.attributes.playParams.id ?? self.item.id })
|
let type = self.item.attributes.playParams?.kind ?? self.item.type
|
||||||
|
if (type == "podcast-episodes") {type = "episode"}
|
||||||
|
app.mk.playLater({ [type]: self.item.attributes.playParams?.id ?? self.item.id })
|
||||||
app.mk.queue._reindex()
|
app.mk.queue._reindex()
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
}
|
}
|
||||||
|
@ -418,7 +429,7 @@
|
||||||
"icon": "./assets/feather/radio.svg",
|
"icon": "./assets/feather/radio.svg",
|
||||||
"name": app.getLz('action.startRadio'),
|
"name": app.getLz('action.startRadio'),
|
||||||
"action": function () {
|
"action": function () {
|
||||||
app.mk.setStationQueue({ song: self.item.attributes.playParams.id ?? self.item.id }).then(() => {
|
app.mk.setStationQueue({ song: self.item.attributes.playParams?.id ?? self.item.id }).then(() => {
|
||||||
app.mk.play()
|
app.mk.play()
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
})
|
})
|
||||||
|
@ -444,7 +455,7 @@
|
||||||
"action": function () {
|
"action": function () {
|
||||||
if (!self.item.attributes.url && self.item.relationships) {
|
if (!self.item.attributes.url && self.item.relationships) {
|
||||||
if (self.item.relationships.catalog) {
|
if (self.item.relationships.catalog) {
|
||||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
|
app.mkapi(self.item.attributes.playParams?.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.app.copyToClipboard(self.item.attributes.url)
|
self.app.copyToClipboard(self.item.attributes.url)
|
||||||
|
@ -457,7 +468,7 @@
|
||||||
"action": function () {
|
"action": function () {
|
||||||
if (!self.item.attributes.url && self.item.relationships) {
|
if (!self.item.attributes.url && self.item.relationships) {
|
||||||
if (self.item.relationships.catalog) {
|
if (self.item.relationships.catalog) {
|
||||||
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
|
app.mkapi(self.item.attributes.playParams?.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.app.songLinkShare(self.item.attributes.url)
|
self.app.songLinkShare(self.item.attributes.url)
|
||||||
|
@ -526,9 +537,9 @@
|
||||||
},
|
},
|
||||||
addToLibrary() {
|
addToLibrary() {
|
||||||
let item = this.item
|
let item = this.item
|
||||||
if (item.attributes.playParams.id) {
|
if (item.attributes.playParams?.id) {
|
||||||
console.log('adding to library', item.attributes.playParams.id)
|
console.log('adding to library', item.attributes.playParams?.id)
|
||||||
app.addToLibrary(item.attributes.playParams.id.toString())
|
app.addToLibrary(item.attributes.playParams?.id.toString())
|
||||||
this.addedToLibrary = true
|
this.addedToLibrary = true
|
||||||
} else if (item.id) {
|
} else if (item.id) {
|
||||||
console.log('adding to library', item.id)
|
console.log('adding to library', item.id)
|
||||||
|
@ -539,14 +550,14 @@
|
||||||
async removeFromLibrary() {
|
async removeFromLibrary() {
|
||||||
let item = this.item
|
let item = this.item
|
||||||
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library" }
|
||||||
let id = item.id ?? item.attributes.playParams.id
|
let id = item.id ?? item.attributes.playParams?.id
|
||||||
let res = await app.mkapi(item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.playParams.id ?? item.id, params);
|
let res = await app.mkapi(item.attributes.playParams?.kind ?? item.type, item.attributes.playParams?.isLibrary ?? false, item.attributes.playParams?.id ?? item.id, params);
|
||||||
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) {
|
||||||
id = res.relationships.library.data[0].id
|
id = res.relationships.library.data[0].id
|
||||||
}
|
}
|
||||||
let kind = this.item.attributes.playParams.kind ?? this.data.item ?? '';
|
let kind = this.item.attributes.playParams?.kind ?? this.data.item ?? '';
|
||||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||||
if (item.attributes.playParams.id) {
|
if (item.attributes.playParams?.id) {
|
||||||
console.log('remove from library', id)
|
console.log('remove from library', id)
|
||||||
app.removeFromLibrary(truekind, id)
|
app.removeFromLibrary(truekind, id)
|
||||||
this.addedToLibrary = false
|
this.addedToLibrary = false
|
||||||
|
@ -560,9 +571,9 @@
|
||||||
let item = this.item
|
let item = this.item
|
||||||
let parent = this.parent
|
let parent = this.parent
|
||||||
let childIndex = this.index
|
let childIndex = this.index
|
||||||
let kind = (item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')) : (item.type ?? ''));
|
let kind = (item.attributes.playParams ? (item.attributes.playParams?.kind ?? (item.type ?? '')) : (item.type ?? ''));
|
||||||
let id = (item.attributes.playParams ? (item.attributes.playParams.id ?? (item.id ?? '')) : (item.id ?? ''));;
|
let id = (item.attributes.playParams ? (item.attributes.playParams?.id ?? (item.id ?? '')) : (item.id ?? ''));;
|
||||||
let isLibrary = item.attributes.playParams ? (item.attributes.playParams.isLibrary ?? false) : false;
|
let isLibrary = item.attributes.playParams ? (item.attributes.playParams?.isLibrary ?? false) : false;
|
||||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||||
console.log(item, parent, childIndex, kind, id, isLibrary, kind == "playlists", id.startsWith("p.") || id.startsWith("pl.u"))
|
console.log(item, parent, childIndex, kind, id, isLibrary, kind == "playlists", id.startsWith("p.") || id.startsWith("pl.u"))
|
||||||
app.mk.stop().then(() => {
|
app.mk.stop().then(() => {
|
||||||
|
@ -578,7 +589,7 @@
|
||||||
array[j] = temp;
|
array[j] = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.mk.setQueue({ [truekind]: [item.attributes.playParams.id ?? item.id], parameters: { l: this.app.mklang } }).then(function () {
|
app.mk.setQueue({ [truekind]: [item.attributes.playParams?.id ?? item.id], parameters: { l: this.app.mklang } }).then(function () {
|
||||||
app.mk.play().then(function () {
|
app.mk.play().then(function () {
|
||||||
var playlistId = id
|
var playlistId = id
|
||||||
function getPlaylist(id, isLibrary) {
|
function getPlaylist(id, isLibrary) {
|
||||||
|
@ -624,12 +635,12 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
app.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url)
|
app.playMediaItemById(item.attributes.playParams?.id ?? item.id, item.attributes.playParams?.kind ?? item.type, item.attributes.playParams?.isLibrary ?? false, item.attributes.url)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
route() {
|
route() {
|
||||||
let kind = (this.item.attributes.playParams ? (this.item.attributes.playParams.kind ?? (this.item.type ?? '')) : (this.item.type ?? ''));
|
let kind = (this.item.attributes.playParams ? (this.item.attributes.playParams?.kind ?? (this.item.type ?? '')) : (this.item.type ?? ''));
|
||||||
if (kind.toLowerCase().includes('album') || kind.toLowerCase().includes('playlist')) {
|
if (kind.toLowerCase().includes('album') || kind.toLowerCase().includes('playlist')) {
|
||||||
app.routeView(this.item)
|
app.routeView(this.item)
|
||||||
} else {
|
} else {
|
||||||
|
|
65
src/renderer/views/components/pathmenu.ejs
Normal file
65
src/renderer/views/components/pathmenu.ejs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<script type="text/x-template" id="pathmenu">
|
||||||
|
<div class="spatialproperties-panel castmenu pathmenu modal-fullscreen" @click.self="close()" @contextmenu.self="close()">
|
||||||
|
<div class="modal-window">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-title">{{'Edit Paths'}}</div>
|
||||||
|
<button class="close-btn" @click="close()" :aria-label="$root.getLz('action.close')"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-content">
|
||||||
|
<template v-for="folder of folders">
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
{{folder}}
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<button class="md-btn" @click="remove(folder)">
|
||||||
|
{{'Remove'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<button class="md-btn" @click="add()">
|
||||||
|
{{'Add Path'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
Vue.component('pathmenu', {
|
||||||
|
template: '#pathmenu',
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
folders: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.folders = this.$root.cfg.libraryPrefs.localPaths;
|
||||||
|
},
|
||||||
|
watch:{},
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.$root.modals.pathMenu = false
|
||||||
|
},
|
||||||
|
async add(){
|
||||||
|
const result = await ipcRenderer.invoke('folderSelector')
|
||||||
|
for (i of result){
|
||||||
|
if (this.folders.findIndex(x => x.startsWith(i)) == -1){
|
||||||
|
this.folders.push(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||||
|
ipcRenderer.invoke("scanLibrary")
|
||||||
|
},
|
||||||
|
remove(dir){
|
||||||
|
this.folders = this.folders.filter(item => item !== dir)
|
||||||
|
this.$root.cfg.libraryPrefs.localPaths = this.folders;
|
||||||
|
ipcRenderer.invoke("scanLibrary")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -228,6 +228,16 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
{{'Local files path'}}
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<button class="md-btn" @click="openLocalSongsPathMenu">
|
||||||
|
{{'Edit Paths'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1893,8 +1903,11 @@
|
||||||
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
|
||||||
if (ok) ipcRenderer.invoke("relaunchApp")
|
if (ok) ipcRenderer.invoke("relaunchApp")
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
/* keybindings */
|
/* keybindings */
|
||||||
|
openLocalSongsPathMenu() {
|
||||||
|
app.modals.pathMenu = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
|
@ -207,7 +207,44 @@
|
||||||
openPlaylist(item) {
|
openPlaylist(item) {
|
||||||
this.$root.appRoute(`playlist_` + item.id);
|
this.$root.appRoute(`playlist_` + item.id);
|
||||||
this.$root.showingPlaylist = [];
|
this.$root.showingPlaylist = [];
|
||||||
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
if (item.id == 'ciderlocal') {
|
||||||
|
this.$root.showingPlaylist = {
|
||||||
|
"id": "ciderlocal",
|
||||||
|
"type": "library-playlists",
|
||||||
|
"href": "",
|
||||||
|
"attributes": {
|
||||||
|
"artwork": {
|
||||||
|
"width": null,
|
||||||
|
"height": null,
|
||||||
|
"url": "",
|
||||||
|
"hasP3": false
|
||||||
|
},
|
||||||
|
"dateAdded": "2021-02-16T03:39:47Z",
|
||||||
|
"name": "Local Songs",
|
||||||
|
"canDelete": true,
|
||||||
|
"hasCatalog": true,
|
||||||
|
"canEdit": true,
|
||||||
|
"playParams": {
|
||||||
|
"id": "ciderlocal",
|
||||||
|
"kind": "playlist",
|
||||||
|
"isLibrary": true,
|
||||||
|
},
|
||||||
|
"isPublic": true,
|
||||||
|
"description": {
|
||||||
|
"standard": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relationships": {
|
||||||
|
"tracks": {
|
||||||
|
"href": "",
|
||||||
|
"data": this.$root.library.localsongs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$root.playlists.loadingState = 1;
|
||||||
|
} else {
|
||||||
|
this.$root.getPlaylistFromID(this.$root.page.substring(9), true)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
getPlaylistChildren(item) {
|
getPlaylistChildren(item) {
|
||||||
let self = this
|
let self = this
|
||||||
|
|
|
@ -138,7 +138,16 @@
|
||||||
>
|
>
|
||||||
</sidebar-library-item>
|
</sidebar-library-item>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="$root.cfg.libraryPrefs.localPaths.length != 0 && $root.cfg.advanced.experiments.includes('localLibrary')">
|
||||||
|
<div class="app-sidebar-header-text"
|
||||||
|
@click="$root.cfg.general.sidebarCollapsed.localLibrary = !$root.cfg.general.sidebarCollapsed.localLibrary"
|
||||||
|
:class="{collapsed: $root.cfg.general.sidebarCollapsed.localLibrary}">
|
||||||
|
Local Library
|
||||||
|
</div>
|
||||||
|
<template v-if="!$root.cfg.general.sidebarCollapsed.localLibrary">
|
||||||
|
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}">
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
<template v-if="$root.getPlaylistFolderChildren('p.applemusic').length != 0">
|
<template v-if="$root.getPlaylistFolderChildren('p.applemusic').length != 0">
|
||||||
<div
|
<div
|
||||||
class="app-sidebar-header-text"
|
class="app-sidebar-header-text"
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
@click="openInfoModal()"></div>
|
@click="openInfoModal()"></div>
|
||||||
<div v-else-if="((data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null) && (descriptionEditing == false)"
|
<div v-else-if="((data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null) && (descriptionEditing == false)"
|
||||||
@mouseover="minClass(false)" @click="editPlaylistDescription()" v-html="(data.attributes.description?.standard ?? (data.attributes.editorialNotes?.standard ?? '')).substring(0, 255) +'...'"
|
@mouseover="minClass(false)" @click="editPlaylistDescription()" v-html="(data.attributes.description?.standard ?? (data.attributes.editorialNotes?.standard ?? '')).substring(0, 255) +'...'"
|
||||||
@click="if((data.attributes.description?.standard ?? (data.attributes.editorialNotes?.standard ?? '')).length > 255) {openInfoModal()}"></div>
|
></div>
|
||||||
<div v-else-if="((data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null) && (descriptionEditing)"
|
<div v-else-if="((data.attributes.description?.standard ?? data.attributes.editorialNotes?.standard) != null) && (descriptionEditing)"
|
||||||
@mouseover="minClass(false)"><input type="text"
|
@mouseover="minClass(false)"><input type="text"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
|
@ -195,7 +195,7 @@
|
||||||
<template v-if="!hasNestedPlaylist">
|
<template v-if="!hasNestedPlaylist">
|
||||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
|
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index"
|
||||||
:showIndex="true"
|
:showIndex="true"
|
||||||
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
:showIndexPlaylist="(data.attributes.playParams?.kind ?? data.type ?? '').includes('playlist')"
|
||||||
:context-ext="buildContextMenu()"
|
:context-ext="buildContextMenu()"
|
||||||
v-for="(item,index) in displayListing"></mediaitem-list-item>
|
v-for="(item,index) in displayListing"></mediaitem-list-item>
|
||||||
</template>
|
</template>
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)"
|
<mediaitem-list-item :item="item" :parent="getItemParent(data)"
|
||||||
:index="index"
|
:index="index"
|
||||||
:showIndex="true"
|
:showIndex="true"
|
||||||
:showIndexPlaylist="(data.attributes.playParams.kind ?? data.type ?? '').includes('playlist')"
|
:showIndexPlaylist="(data.attributes.playParams?.kind ?? data.type ?? '').includes('playlist')"
|
||||||
:context-ext="buildContextMenu()"
|
:context-ext="buildContextMenu()"
|
||||||
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
|
v-for="(item,index) in disc.tracks"></mediaitem-list-item>
|
||||||
</div>
|
</div>
|
||||||
|
@ -305,17 +305,24 @@
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
this.isInLibrary()
|
if (this.data.id != "ciderlocal") {
|
||||||
})
|
this.isInLibrary()
|
||||||
|
} else {
|
||||||
|
if (this.data.relationships != null && this.data.id == "ciderlocal") {
|
||||||
|
this.displayListing = this.data.relationships.tracks.data
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inPlaylist = this.data.type == "library-playlists";
|
||||||
|
}})
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
if( window.location.hash.includes("playlist") ) {
|
if (window.location.hash.includes("playlist")) {
|
||||||
window.addEventListener('keydown', this.getCopiedPlayListSongs);
|
window.addEventListener('keydown', this.getCopiedPlayListSongs);
|
||||||
window.addEventListener('keydown', this.pasteSongs);
|
window.addEventListener('keydown', this.pasteSongs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if( window.location.hash.includes("playlist") ) {
|
if (window.location.hash.includes("playlist")) {
|
||||||
window.removeEventListener('keydown', this.getCopiedPlayListSongs);
|
window.removeEventListener('keydown', this.getCopiedPlayListSongs);
|
||||||
window.removeEventListener('keydown', this.pasteSongs);
|
window.removeEventListener('keydown', this.pasteSongs);
|
||||||
}
|
}
|
||||||
|
@ -326,10 +333,14 @@
|
||||||
this.isInLibrary()
|
this.isInLibrary()
|
||||||
this.getBadges()
|
this.getBadges()
|
||||||
|
|
||||||
if (this.data.relationships) {
|
if (this.data.relationships != null) {
|
||||||
this.generateNestedPlaylist(this.data.relationships.tracks.data)
|
if (this.data.id == "ciderlocal") {
|
||||||
if (!this.hasNestedPlaylist) {
|
|
||||||
this.displayListing = this.data.relationships.tracks.data
|
this.displayListing = this.data.relationships.tracks.data
|
||||||
|
} else {
|
||||||
|
this.generateNestedPlaylist(this.data.relationships.tracks.data)
|
||||||
|
if (!this.hasNestedPlaylist) {
|
||||||
|
this.displayListing = this.data.relationships.tracks.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,21 +393,21 @@
|
||||||
this.headerVisible = visible
|
this.headerVisible = visible
|
||||||
},
|
},
|
||||||
hasHero() {
|
hasHero() {
|
||||||
if(this.data.attributes?.editorialArtwork?.bannerUber){
|
if (this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||||
return this.data.attributes?.editorialArtwork?.bannerUber.url
|
return this.data.attributes?.editorialArtwork?.bannerUber.url
|
||||||
} else if(this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
} else if (this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
||||||
return this.data.attributes?.editorialArtwork?.subscriptionHero.url
|
return this.data.attributes?.editorialArtwork?.subscriptionHero.url
|
||||||
} else if(this.data.attributes?.editorialArtwork?.storeFlowcase){
|
} else if (this.data.attributes?.editorialArtwork?.storeFlowcase) {
|
||||||
return this.data.attributes?.editorialArtwork?.storeFlowcase.url
|
return this.data.attributes?.editorialArtwork?.storeFlowcase.url
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
hasHeroObject() {
|
hasHeroObject() {
|
||||||
if(this.data.attributes?.editorialArtwork?.bannerUber){
|
if (this.data.attributes?.editorialArtwork?.bannerUber) {
|
||||||
return this.data.attributes?.editorialArtwork?.bannerUber
|
return this.data.attributes?.editorialArtwork?.bannerUber
|
||||||
} else if(this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
} else if (this.data.attributes?.editorialArtwork?.subscriptionHero) {
|
||||||
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
return this.data.attributes?.editorialArtwork?.subscriptionHero
|
||||||
} else if(this.data.attributes?.editorialArtwork?.storeFlowcase){
|
} else if (this.data.attributes?.editorialArtwork?.storeFlowcase) {
|
||||||
return this.data.attributes?.editorialArtwork?.storeFlowcase
|
return this.data.attributes?.editorialArtwork?.storeFlowcase
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
|
@ -774,14 +785,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = this.data.attributes.playParams.id ?? this.data.id;
|
const id = this.data.attributes.playParams?.id ?? this.data.id;
|
||||||
//console.log("1")
|
//console.log("1")
|
||||||
const kind = this.data.attributes.playParams.kind ?? this.data.type ?? '';
|
const kind = this.data.attributes.playParams?.kind ?? this.data.type ?? '';
|
||||||
//console.log("1")
|
//console.log("1")
|
||||||
|
if (kind == "podcast-episodes") {kind = "episode"}
|
||||||
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||||
|
|
||||||
let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
|
let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item));
|
||||||
app.mk.stop().then(function () {
|
|
||||||
|
app.mk.stop().then(() => {
|
||||||
|
if (id != 'ciderlocal'){
|
||||||
app.mk.setQueue({ [truekind]: [id], parameters: { l: app.mklang } }).then(function () {
|
app.mk.setQueue({ [truekind]: [id], parameters: { l: app.mklang } }).then(function () {
|
||||||
app.mk.play().then(function () {
|
app.mk.play().then(function () {
|
||||||
if (query.length > 100) {
|
if (query.length > 100) {
|
||||||
|
@ -792,7 +806,12 @@
|
||||||
app.mk.queue.append(u)
|
app.mk.queue.append(u)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})} else {
|
||||||
|
let u = app.library.localsongs.map(i => {return i.id})
|
||||||
|
app.mk.setQueue({"episodes" : u}).then(()=>{
|
||||||
|
app.mk.play()
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -802,7 +821,7 @@
|
||||||
return "d-none";
|
return "d-none";
|
||||||
},
|
},
|
||||||
async getCopiedPlayListSongs(event) {
|
async getCopiedPlayListSongs(event) {
|
||||||
if( event.ctrlKey && event.keyCode === 67 ) {
|
if (event.ctrlKey && event.keyCode === 67) {
|
||||||
let urls = [];
|
let urls = [];
|
||||||
app.selectedMediaItems.forEach(item => {
|
app.selectedMediaItems.forEach(item => {
|
||||||
this.app.mk.api.v3.music(`/v1/me/library/songs/${item.id}`).then((response) => {
|
this.app.mk.api.v3.music(`/v1/me/library/songs/${item.id}`).then((response) => {
|
||||||
|
@ -816,14 +835,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async pasteSongs(event) {
|
async pasteSongs(event) {
|
||||||
if( event.ctrlKey && event.keyCode === 86 && this.data.attributes.canEdit ) {
|
if (event.ctrlKey && event.keyCode === 86 && this.data.attributes.canEdit) {
|
||||||
let clipboard = await navigator.clipboard.readText()
|
let clipboard = await navigator.clipboard.readText()
|
||||||
let songs = []
|
let songs = []
|
||||||
|
|
||||||
clipboard = clipboard.split(",")
|
clipboard = clipboard.split(",")
|
||||||
clipboard.forEach(item => {
|
clipboard.forEach(item => {
|
||||||
songs.push({
|
songs.push({
|
||||||
id: item.substring(item.indexOf("i=")+2, item.length),
|
id: item.substring(item.indexOf("i=") + 2, item.length),
|
||||||
type: "songs",
|
type: "songs",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -220,6 +220,16 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
{{'Local files path'}}
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<button class="md-btn" @click="openLocalSongsPathMenu">
|
||||||
|
{{'Edit Paths'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</b-tab>
|
</b-tab>
|
||||||
|
@ -1147,7 +1157,6 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</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.reinstallwidevine')}}
|
{{$root.getLz('settings.option.experimental.reinstallwidevine')}}
|
||||||
|
@ -1523,6 +1532,9 @@
|
||||||
},
|
},
|
||||||
filterChange(e) {
|
filterChange(e) {
|
||||||
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked;
|
||||||
|
},
|
||||||
|
openLocalSongsPathMenu() {
|
||||||
|
app.modals.pathMenu = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"paths": {
|
"paths": {
|
||||||
"*": ["node_modules/*"]
|
"*": ["node_modules/*"]
|
||||||
},
|
},
|
||||||
|
"skipLibCheck": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/musickit-typescript",
|
"node_modules/musickit-typescript",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue