Merge branch 'ciderapp:develop' into develop
This commit is contained in:
commit
20036aeafd
30 changed files with 890 additions and 312 deletions
|
@ -56,6 +56,11 @@ jobs:
|
||||||
command: yarn dist -w --x64 -p never
|
command: yarn dist -w --x64 -p never
|
||||||
post-steps:
|
post-steps:
|
||||||
- jira/notify
|
- jira/notify
|
||||||
|
- run:
|
||||||
|
name: Generate Builds (Winget)
|
||||||
|
command: yarn winget -p never
|
||||||
|
post-steps:
|
||||||
|
- jira/notify
|
||||||
- run:
|
- run:
|
||||||
name: Move Build Files
|
name: Move Build Files
|
||||||
command: |
|
command: |
|
||||||
|
|
1
.github/workflows/build-macos.yml
vendored
1
.github/workflows/build-macos.yml
vendored
|
@ -92,6 +92,7 @@ jobs:
|
||||||
rm cider-yarn.lock || true
|
rm cider-yarn.lock || true
|
||||||
xcodebuild -version
|
xcodebuild -version
|
||||||
yarn install
|
yarn install
|
||||||
|
cp resources/verror-types node_modules/@types/verror/index.d.ts
|
||||||
cp resources/macPackager.js node_modules/app-builder-lib/out/macPackager.js
|
cp resources/macPackager.js node_modules/app-builder-lib/out/macPackager.js
|
||||||
yarn dist:universalNotWorking -p never
|
yarn dist:universalNotWorking -p never
|
||||||
# - name: Perform CodeQL Analysis
|
# - name: Perform CodeQL Analysis
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"dist:macarm": "yarn build && electron-builder --mac --arm64",
|
"dist:macarm": "yarn build && electron-builder --mac --arm64",
|
||||||
"dist:universalNotWorking": "yarn build && electron-builder --mac --universal",
|
"dist:universalNotWorking": "yarn build && electron-builder --mac --universal",
|
||||||
"dist:all": "yarn build && electron-builder -mwl",
|
"dist:all": "yarn build && electron-builder -mwl",
|
||||||
|
"winget": "yarn build && electron-builder --win -c winget.json",
|
||||||
"msft": "yarn build && electron-builder -c msft-package.json",
|
"msft": "yarn build && electron-builder -c msft-package.json",
|
||||||
"postinstall": "electron-builder install-app-deps",
|
"postinstall": "electron-builder install-app-deps",
|
||||||
"circle:append-bid": "node resources/appendCommitToVersion"
|
"circle:append-bid": "node resources/appendCommitToVersion"
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/electron": "^3.0.2",
|
"@sentry/electron": "^3.0.2",
|
||||||
"@sentry/integrations": "^6.18.1",
|
"@sentry/integrations": "^6.18.1",
|
||||||
"adm-zip": "^0.5.9",
|
"adm-zip": "0.4.10",
|
||||||
"castv2-client": "^1.2.0",
|
"castv2-client": "^1.2.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"discord-rpc": "^4.0.1",
|
"discord-rpc": "^4.0.1",
|
||||||
|
|
77
resources/verror-types
Normal file
77
resources/verror-types
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Type definitions for verror 1.10
|
||||||
|
// Project: https://github.com/davepacheco/node-verror
|
||||||
|
// Definitions by: Sven Reglitzki <https://github.com/svi3c>, Maxime Toumi-M <https://github.com/max4t>
|
||||||
|
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VError([cause], fmt[, arg...]): Like JavaScript's built-in Error class, but
|
||||||
|
* supports a "cause" argument (another error) and a printf-style message. The
|
||||||
|
* cause argument can be null or omitted entirely.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* CODE MESSAGE
|
||||||
|
* new VError('something bad happened') "something bad happened"
|
||||||
|
* new VError('missing file: "%s"', file) "missing file: "/etc/passwd"
|
||||||
|
* with file = '/etc/passwd'
|
||||||
|
* new VError(err, 'open failed') "open failed: file not found"
|
||||||
|
* with err.message = 'file not found'
|
||||||
|
*/
|
||||||
|
declare class VError extends Error {
|
||||||
|
static VError: typeof VError;
|
||||||
|
|
||||||
|
static cause(err: Error): Error | null;
|
||||||
|
static info(err: Error): VError.Info;
|
||||||
|
static fullStack(err: Error): string;
|
||||||
|
static findCauseByName(err: Error, name: string): Error | null;
|
||||||
|
static hasCauseWithName(err: Error, name: string): boolean;
|
||||||
|
static errorFromList<T extends Error>(errors: T[]): null | T | VError.MultiError;
|
||||||
|
static errorForEach(err: Error, func: (err: Error) => void): void;
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
cause(): Error | undefined;
|
||||||
|
constructor(options: VError.Options | Error, message: string, ...params: any[]);
|
||||||
|
constructor(message?: string, ...params: any[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace VError {
|
||||||
|
interface Info {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
cause?: Error | null | undefined;
|
||||||
|
name?: string | undefined;
|
||||||
|
strict?: boolean | undefined;
|
||||||
|
constructorOpt?(...args: any[]): void;
|
||||||
|
info?: Info | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SError is like VError, but stricter about types. You cannot pass "null" or
|
||||||
|
* "undefined" as string arguments to the formatter. Since SError is only a
|
||||||
|
* different function, not really a different class, we don't set
|
||||||
|
* SError.prototype.name.
|
||||||
|
*/
|
||||||
|
class SError extends VError {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Represents a collection of errors for the purpose of consumers that generally
|
||||||
|
* only deal with one error. Callers can extract the individual errors
|
||||||
|
* contained in this object, but may also just treat it as a normal single
|
||||||
|
* error, in which case a summary message will be printed.
|
||||||
|
*/
|
||||||
|
class MultiError extends VError {
|
||||||
|
constructor(errors: Error[]);
|
||||||
|
errors(): Error[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like JavaScript's built-in Error class, but supports a "cause" argument which
|
||||||
|
* is wrapped, not "folded in" as with VError. Accepts a printf-style message.
|
||||||
|
* The cause argument can be null.
|
||||||
|
*/
|
||||||
|
class WError extends VError {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export = VError;
|
|
@ -10,6 +10,6 @@
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Normalises peak volume for individual tracks to create a more uniform listening experience.",
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Normalises peak volume for individual tracks to create a more uniform listening experience.",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Audio Spatialisation",
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Audio Spatialisation",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Spatialise audio and make audio more 3-dimensional (note: This is not Dolby Atmos)",
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Spatialise audio and make audio more 3-dimensional (note: This is not Dolby Atmos)",
|
||||||
"spatial.notTurnedOn": "Audio Spatialisation is disabled. To use, please enable it first."
|
"spatial.notTurnedOn": "Audio Spatialisation is disabled. To use, please enable it first.",
|
||||||
"action.tray.minimize": "Minimise to Tray",
|
"action.tray.minimize": "Minimise to Tray"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"i18n.languageName": "English (US)",
|
"i18n.languageName": "English (US)",
|
||||||
"i18n.languageNameEnglish": "English (US)",
|
"i18n.languageNameEnglish": "English (US)",
|
||||||
"i18n.category": "main",
|
"i18n.category": "main",
|
||||||
"i18n.authors": "@maikirakiwi @kyw504100",
|
"i18n.authors": "@maikirakiwi @kyw504100 nosh118",
|
||||||
"app.name": "Cider",
|
"app.name": "Cider",
|
||||||
"date.format": "${m} ${d}, ${y}",
|
"date.format": "${m} ${d}, ${y}",
|
||||||
"dialog.cancel": "Cancel",
|
"dialog.cancel": "Cancel",
|
||||||
|
@ -89,6 +89,8 @@
|
||||||
"term.time.added": "Added",
|
"term.time.added": "Added",
|
||||||
"term.time.released": "Released",
|
"term.time.released": "Released",
|
||||||
"term.time.updated": "Updated",
|
"term.time.updated": "Updated",
|
||||||
|
"term.time.days": "days",
|
||||||
|
"term.time.day": "day",
|
||||||
"term.time.hours": "hours",
|
"term.time.hours": "hours",
|
||||||
"term.time.hour": "hour",
|
"term.time.hour": "hour",
|
||||||
"term.time.minutes": "minutes",
|
"term.time.minutes": "minutes",
|
||||||
|
@ -115,6 +117,10 @@
|
||||||
"term.equalizer": "Equalizer",
|
"term.equalizer": "Equalizer",
|
||||||
"term.reset": "Reset",
|
"term.reset": "Reset",
|
||||||
"term.tracks": "tracks",
|
"term.tracks": "tracks",
|
||||||
|
"term.track": {
|
||||||
|
"one" : "track",
|
||||||
|
"other" : "tracks"
|
||||||
|
},
|
||||||
"term.videos": "Videos",
|
"term.videos": "Videos",
|
||||||
"term.menu": "Menu",
|
"term.menu": "Menu",
|
||||||
"term.check": "Check",
|
"term.check": "Check",
|
||||||
|
@ -142,7 +148,6 @@
|
||||||
"term.noVideos": "No videos found.",
|
"term.noVideos": "No videos found.",
|
||||||
"term.plugin": "Plug-in",
|
"term.plugin": "Plug-in",
|
||||||
"term.pluginMenu": "Plug-in Menu",
|
"term.pluginMenu": "Plug-in Menu",
|
||||||
"term.pluginMenu.none": "No interactive plugins.",
|
|
||||||
"term.replay": "Replay",
|
"term.replay": "Replay",
|
||||||
"term.uniqueAlbums": "Unique Albums",
|
"term.uniqueAlbums": "Unique Albums",
|
||||||
"term.uniqueArtists": "Unique Artists",
|
"term.uniqueArtists": "Unique Artists",
|
||||||
|
@ -158,7 +163,7 @@
|
||||||
"home.recentlyPlayed": "Recently Played",
|
"home.recentlyPlayed": "Recently Played",
|
||||||
"home.recentlyAdded": "Recently Added",
|
"home.recentlyAdded": "Recently Added",
|
||||||
"home.artistsFeed": "Your Artists Feed",
|
"home.artistsFeed": "Your Artists Feed",
|
||||||
"home.artistsFeed.noArtist": "Follow some artists first and their latest releases will be here",
|
"home.artistsFeed.noArtist": "Follow some artists to see their latest releases",
|
||||||
"home.madeForYou": "Made For You",
|
"home.madeForYou": "Made For You",
|
||||||
"home.friendsListeningTo": "Friends Listening To",
|
"home.friendsListeningTo": "Friends Listening To",
|
||||||
"home.followedArtists": "Followed Artists",
|
"home.followedArtists": "Followed Artists",
|
||||||
|
@ -240,6 +245,10 @@
|
||||||
"settings.option.general.updateCider.branch.description": "Select the branch to update Cider to",
|
"settings.option.general.updateCider.branch.description": "Select the branch to update Cider to",
|
||||||
"settings.option.general.updateCider.branch.main": "Stable",
|
"settings.option.general.updateCider.branch.main": "Stable",
|
||||||
"settings.option.general.updateCider.branch.develop": "Development",
|
"settings.option.general.updateCider.branch.develop": "Development",
|
||||||
|
"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-error": "Error updating Cider",
|
||||||
|
"settings.notyf.updateCider.update-timeout": "Update timed out",
|
||||||
"settings.header.audio": "Audio",
|
"settings.header.audio": "Audio",
|
||||||
"settings.header.audio.description": "Adjust the audio settings for Cider.",
|
"settings.header.audio.description": "Adjust the audio settings for Cider.",
|
||||||
"settings.option.audio.volumeStep": "Volume Step",
|
"settings.option.audio.volumeStep": "Volume Step",
|
||||||
|
@ -255,7 +264,7 @@
|
||||||
"settings.header.audio.quality.standard.description": "64 kbps",
|
"settings.header.audio.quality.standard.description": "64 kbps",
|
||||||
"settings.option.audio.seamlessTransition": "Seamless Audio Transition",
|
"settings.option.audio.seamlessTransition": "Seamless Audio Transition",
|
||||||
"settings.option.audio.enableAdvancedFunctionality": "Enable Advanced Functionality",
|
"settings.option.audio.enableAdvancedFunctionality": "Enable Advanced Functionality",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.description": "Enabling AudioContext functionality will allow for extended audio features like Audio Normalization , Equalizers and Visualizers, however on some systems this may cause stuttering in audio tracks.",
|
"settings.option.audio.enableAdvancedFunctionality.description": "Enabling AudioContext functionality will allow for extended audio features like Audio Normalization, Equalizers and Visualizers - however on some systems this may cause stuttering in audio tracks.",
|
||||||
"settings.option.audio.audioLab": "Cider Audio Lab",
|
"settings.option.audio.audioLab": "Cider Audio Lab",
|
||||||
"settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.",
|
"settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.",
|
||||||
"settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.",
|
"settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.",
|
||||||
|
|
|
@ -219,6 +219,7 @@ export class AppEvents {
|
||||||
app.quit()
|
app.quit()
|
||||||
} else if (utils.getWindow()) {
|
} else if (utils.getWindow()) {
|
||||||
if (utils.getWindow().isMinimized()) utils.getWindow().restore()
|
if (utils.getWindow().isMinimized()) utils.getWindow().restore()
|
||||||
|
utils.getWindow().show()
|
||||||
utils.getWindow().focus()
|
utils.getWindow().focus()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,6 +12,7 @@ import fetch from 'electron-fetch'
|
||||||
import {wsapi} from "./wsapi";
|
import {wsapi} from "./wsapi";
|
||||||
import {AppImageUpdater, NsisUpdater} from "electron-updater";
|
import {AppImageUpdater, NsisUpdater} from "electron-updater";
|
||||||
import {utils} from './utils';
|
import {utils} from './utils';
|
||||||
|
|
||||||
const fileWatcher = require('chokidar');
|
const fileWatcher = require('chokidar');
|
||||||
const AdmZip = require("adm-zip");
|
const AdmZip = require("adm-zip");
|
||||||
|
|
||||||
|
@ -233,6 +234,7 @@ export class BrowserWindow {
|
||||||
preload: join(utils.getPath('srcPath'), "./preload/cider-preload.js"),
|
preload: join(utils.getPath('srcPath'), "./preload/cider-preload.js"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
StartWatcher(path: string) {
|
StartWatcher(path: string) {
|
||||||
var chokidar = require("chokidar");
|
var chokidar = require("chokidar");
|
||||||
|
|
||||||
|
@ -272,6 +274,7 @@ export class BrowserWindow {
|
||||||
// console.log('Raw event info:', event, path, details);
|
// console.log('Raw event info:', event, path, details);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the browser window
|
* Creates the browser window
|
||||||
*/
|
*/
|
||||||
|
@ -590,10 +593,33 @@ export class BrowserWindow {
|
||||||
let response = await fetch(
|
let response = await fetch(
|
||||||
`${url}/archive/refs/heads/main.zip`
|
`${url}/archive/refs/heads/main.zip`
|
||||||
);
|
);
|
||||||
let zip = await response.buffer();
|
let repo = url.split("/").slice(-2).join("/");
|
||||||
let zipFile = new AdmZip(zip);
|
let apiRepo = await fetch(
|
||||||
zipFile.extractAllTo(utils.getPath("themes"), true);
|
`https://api.github.com/repos/${repo}`
|
||||||
|
).then((res) => res.json());
|
||||||
|
console.debug(`REPO ID: ${apiRepo.id}`);
|
||||||
|
// extract the files from the first folder in the zip response
|
||||||
|
let zip = new AdmZip(await response.buffer());
|
||||||
|
let entry = zip.getEntries()[0];
|
||||||
|
if (!existsSync(join(utils.getPath("themes"), "gh_" + apiRepo.id))) {
|
||||||
|
mkdirSync(join(utils.getPath("themes"), "gh_" + apiRepo.id));
|
||||||
|
}
|
||||||
|
console.log(join(utils.getPath("themes"), "gh_" + apiRepo.id))
|
||||||
|
zip.extractEntryTo(entry, join(utils.getPath("themes"), "gh_" + apiRepo.id), false, true);
|
||||||
|
let commit = await fetch(
|
||||||
|
`https://api.github.com/repos/${repo}/commits`
|
||||||
|
).then((res) => res.json());
|
||||||
|
console.debug(`COMMIT SHA: ${commit[0].sha}`);
|
||||||
|
let theme = JSON.parse(
|
||||||
|
readFileSync(join(utils.getPath("themes"), "gh_" + apiRepo.id, "theme.json"), "utf8")
|
||||||
|
);
|
||||||
|
theme.id = apiRepo.id
|
||||||
|
theme.commit = commit[0].sha;
|
||||||
|
writeFileSync(
|
||||||
|
join(utils.getPath("themes"), "gh_" + apiRepo.id, "theme.json"),
|
||||||
|
JSON.stringify(theme, null, 4),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
returnVal.success = false;
|
returnVal.success = false;
|
||||||
}
|
}
|
||||||
|
@ -635,7 +661,8 @@ export class BrowserWindow {
|
||||||
description: themeJson.description || themeDescription,
|
description: themeJson.description || themeDescription,
|
||||||
path: themePath,
|
path: themePath,
|
||||||
file: theme,
|
file: theme,
|
||||||
github_repo: themeJson.github_repo || ""
|
github_repo: themeJson.github_repo || "",
|
||||||
|
commit: themeJson.commit || ""
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
themeObjects.push({
|
themeObjects.push({
|
||||||
|
@ -643,7 +670,8 @@ export class BrowserWindow {
|
||||||
description: themeDescription,
|
description: themeDescription,
|
||||||
path: themePath,
|
path: themePath,
|
||||||
file: theme,
|
file: theme,
|
||||||
github_repo: ""
|
github_repo: "",
|
||||||
|
commit: ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,6 +682,21 @@ export class BrowserWindow {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle("open-path", async (event, path) => {
|
||||||
|
switch(path) {
|
||||||
|
default:
|
||||||
|
case "plugins":
|
||||||
|
shell.openPath(utils.getPath("plugins"));
|
||||||
|
break;
|
||||||
|
case "userdata":
|
||||||
|
shell.openPath(app.getPath("userData"));
|
||||||
|
break;
|
||||||
|
case "themes":
|
||||||
|
shell.openPath(utils.getPath("themes"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on("get-i18n", (event, key) => {
|
ipcMain.on("get-i18n", (event, key) => {
|
||||||
event.returnValue = utils.getLocale(key);
|
event.returnValue = utils.getLocale(key);
|
||||||
});
|
});
|
||||||
|
|
24
src/main/base/castcontroller.js
Normal file
24
src/main/base/castcontroller.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
var util = require('util');
|
||||||
|
var castv2Cli = require('castv2-client');
|
||||||
|
var RequestResponseController = castv2Cli.RequestResponseController;
|
||||||
|
|
||||||
|
function CiderCastController(client, sourceId, destinationId) {
|
||||||
|
RequestResponseController.call(this, client, sourceId, destinationId, 'urn:x-cast:com.ciderapp.customdata');
|
||||||
|
this.once('close', onclose);
|
||||||
|
var self = this;
|
||||||
|
function onclose() {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(CiderCastController, RequestResponseController);
|
||||||
|
|
||||||
|
CiderCastController.prototype.sendIp = function(ip) {
|
||||||
|
// TODO: Implement Callback
|
||||||
|
let data = {
|
||||||
|
ip : ip
|
||||||
|
}
|
||||||
|
this.request(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = CiderCastController;
|
77
src/main/base/castreceiver.js
Normal file
77
src/main/base/castreceiver.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
//@ts-nocheck
|
||||||
|
var util = require('util');
|
||||||
|
// var debug = require('debug')('castv2-client');
|
||||||
|
var Application = require('castv2-client').Application;
|
||||||
|
var MediaController = require('castv2-client').MediaController;
|
||||||
|
var CiderCastController = require('./castcontroller');
|
||||||
|
|
||||||
|
function CiderReceiver(client, session) {
|
||||||
|
Application.apply(this, arguments);
|
||||||
|
|
||||||
|
this.media = this.createController(MediaController);
|
||||||
|
this.mediaReceiver = this.createController(CiderCastController);
|
||||||
|
|
||||||
|
this.media.on('status', onstatus);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function onstatus(status) {
|
||||||
|
self.emit('status', status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// FE96A351
|
||||||
|
// 27E1334F
|
||||||
|
CiderReceiver.APP_ID = 'FE96A351';
|
||||||
|
|
||||||
|
util.inherits(CiderReceiver, Application);
|
||||||
|
|
||||||
|
CiderReceiver.prototype.getStatus = function(callback) {
|
||||||
|
this.media.getStatus.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.load = function(media, options, callback) {
|
||||||
|
this.media.load.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.play = function(callback) {
|
||||||
|
this.media.play.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.pause = function(callback) {
|
||||||
|
this.media.pause.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.stop = function(callback) {
|
||||||
|
this.media.stop.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.seek = function(currentTime, callback) {
|
||||||
|
this.media.seek.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.queueLoad = function(items, options, callback) {
|
||||||
|
this.media.queueLoad.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.queueInsert = function(items, options, callback) {
|
||||||
|
this.media.queueInsert.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.queueRemove = function(itemIds, options, callback) {
|
||||||
|
this.media.queueRemove.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.queueReorder = function(itemIds, options, callback) {
|
||||||
|
this.media.queueReorder.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.queueUpdate = function(items, callback) {
|
||||||
|
this.media.queueUpdate.apply(this.media, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
CiderReceiver.prototype.sendIp = function(opts){
|
||||||
|
this.mediaReceiver.sendIp.apply(this.mediaReceiver, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = CiderReceiver;
|
|
@ -15,6 +15,7 @@ export class Store {
|
||||||
"update_branch": "main",
|
"update_branch": "main",
|
||||||
"resumeOnStartupBehavior": "local",
|
"resumeOnStartupBehavior": "local",
|
||||||
"privateEnabled": false,
|
"privateEnabled": false,
|
||||||
|
"themeUpdateNotification": true
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"followedArtists": [],
|
"followedArtists": [],
|
||||||
|
@ -96,7 +97,10 @@ export class Store {
|
||||||
"bg_artwork_rotation": false,
|
"bg_artwork_rotation": false,
|
||||||
"hw_acceleration": "default", // default, webgpu, disabled
|
"hw_acceleration": "default", // default, webgpu, disabled
|
||||||
"showuserinfo": true,
|
"showuserinfo": true,
|
||||||
"miniplayer_top_toggle": true
|
"miniplayer_top_toggle": true,
|
||||||
|
"directives": {
|
||||||
|
"windowLayout": "default"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"lyrics": {
|
"lyrics": {
|
||||||
"enable_mxm": false,
|
"enable_mxm": false,
|
||||||
|
|
|
@ -158,6 +158,6 @@ export class utils {
|
||||||
|
|
||||||
log.transports.file.level = "debug"
|
log.transports.file.level = "debug"
|
||||||
autoUpdater.logger = log
|
autoUpdater.logger = log
|
||||||
await autoUpdater.checkForUpdate()
|
await autoUpdater.checkForUpdatesAndNotify()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import {resolve} from 'path';
|
import {resolve} from 'path';
|
||||||
|
import * as CiderReceiver from '../base/castreceiver';
|
||||||
|
|
||||||
export default class ChromecastPlugin {
|
export default class ChromecastPlugin {
|
||||||
|
|
||||||
|
@ -133,9 +134,8 @@ export default class ChromecastPlugin {
|
||||||
|
|
||||||
private loadMedia(client: any, song: any, artist: any, album: any, albumart: any, cb?: any) {
|
private loadMedia(client: any, song: any, artist: any, album: any, albumart: any, cb?: any) {
|
||||||
// const u = 'http://' + this.getIp() + ':' + server.address().port + '/';
|
// const u = 'http://' + this.getIp() + ':' + server.address().port + '/';
|
||||||
const DefaultMediaReceiver : any = require('castv2-client').DefaultMediaReceiver;
|
// const DefaultMediaReceiver : any = require('castv2-client').DefaultMediaReceiver;
|
||||||
|
client.launch(CiderReceiver, (err: any, player: any) => {
|
||||||
client.launch(DefaultMediaReceiver, (err: any, player: any) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return;
|
return;
|
||||||
|
@ -179,6 +179,10 @@ export default class ChromecastPlugin {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// send websocket ip
|
||||||
|
|
||||||
|
player.sendIp("ws://"+this.getIp()+":26369");
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +277,7 @@ export default class ChromecastPlugin {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Plugin Details (Eventually implemented into a GUI in settings)
|
* Base Plugin Details (Eventually implemented into a GUI in settings)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -174,7 +174,11 @@ export default class MPRIS {
|
||||||
*/
|
*/
|
||||||
onBeforeQuit(): void {
|
onBeforeQuit(): void {
|
||||||
console.debug(`[Plugin][${this.name}] Stopped.`);
|
console.debug(`[Plugin][${this.name}] Stopped.`);
|
||||||
|
try {
|
||||||
this.clearState()
|
this.clearState()
|
||||||
|
}catch(e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
6
src/renderer/assets/cider-round.svg
Normal file
6
src/renderer/assets/cider-round.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 1002 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<path d="M501,21C765.367,21 980,235.633 980,500C980,764.367 765.367,979 501,979C236.633,979 22,764.367 22,500C22,235.633 236.633,21 501,21ZM501,169C683.684,169 832,317.316 832,500C832,682.684 683.684,831 501,831C318.316,831 170,682.684 170,500C170,317.316 318.316,169 501,169Z" style="fill:rgb(255,38,84);"/>
|
||||||
|
<path d="M501,224C653.053,224 776.5,347.447 776.5,499.5C776.5,651.553 653.053,775 501,775C348.947,775 225.5,651.553 225.5,499.5C225.5,347.447 348.947,224 501,224ZM589.165,492.207C595.163,495.672 595.163,504.328 589.165,507.793L439.502,594.256C433.502,597.722 426,593.392 426,586.463L426,413.537C426,406.608 433.502,402.278 439.502,405.744L589.165,492.207Z" style="fill:rgb(255,38,84);"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -171,7 +171,7 @@ var CiderAudio = {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._bufferSize = 4096;
|
this._bufferSize = 1024;
|
||||||
this._buffers = null;
|
this._buffers = null;
|
||||||
this._initBuffer();
|
this._initBuffer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,7 @@ const app = new Vue({
|
||||||
playerReady: false,
|
playerReady: false,
|
||||||
animateBackground: false,
|
animateBackground: false,
|
||||||
currentArtUrl: '',
|
currentArtUrl: '',
|
||||||
|
currentArtUrlRaw: '',
|
||||||
lyricon: false,
|
lyricon: false,
|
||||||
currentTrackID: '',
|
currentTrackID: '',
|
||||||
currentTrackIDBG: '',
|
currentTrackIDBG: '',
|
||||||
|
@ -302,7 +303,7 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
songLinkShare(amUrl) {
|
songLinkShare(amUrl) {
|
||||||
notyf.open({type: "info", message: app.getLz('term.song.link.generate')})
|
notyf.open({ type: "info", className: "notyf-info", message: app.getLz('term.song.link.generate') })
|
||||||
let self = this
|
let self = this
|
||||||
httpRequest = new XMLHttpRequest();
|
httpRequest = new XMLHttpRequest();
|
||||||
httpRequest.open('GET', `https://api.song.link/v1-alpha.1/links?url=${amUrl}&userCountry=US`, true);
|
httpRequest.open('GET', `https://api.song.link/v1-alpha.1/links?url=${amUrl}&userCountry=US`, true);
|
||||||
|
@ -903,6 +904,29 @@ const app = new Vue({
|
||||||
this.$forceUpdate()
|
this.$forceUpdate()
|
||||||
}, 500)
|
}, 500)
|
||||||
ipcRenderer.invoke("renderer-ready", true)
|
ipcRenderer.invoke("renderer-ready", true)
|
||||||
|
document.querySelector("#LOADER").remove()
|
||||||
|
if(this.cfg.general.themeUpdateNotification) {
|
||||||
|
this.checkForThemeUpdates()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async checkForThemeUpdates() {
|
||||||
|
let self = this
|
||||||
|
const themes = ipcRenderer.sendSync("get-themes")
|
||||||
|
await asyncForEach(themes, async (theme) => {
|
||||||
|
if (theme.commit != "") {
|
||||||
|
await fetch(`https://api.github.com/repos/${theme.github_repo}/commits`)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => {
|
||||||
|
if (res[0].sha != theme.commit) {
|
||||||
|
const notify = notyf.open({ className: "notyf-info", type: "info", message: `[Themes] ${theme.name} has an update available.` })
|
||||||
|
notify.on("click", ()=>{
|
||||||
|
app.appRoute("themes-github")
|
||||||
|
notyf.dismiss(notify)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async setTheme(theme = "", onlyPrefs = false) {
|
async setTheme(theme = "", onlyPrefs = false) {
|
||||||
console.log(theme)
|
console.log(theme)
|
||||||
|
@ -935,11 +959,14 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getThemeDirective(directive = "") {
|
getThemeDirective(directive = "") {
|
||||||
if(typeof this.chrome.appliedTheme.info.directives != "object") {
|
let directives = {}
|
||||||
return ""
|
if (typeof this.chrome.appliedTheme.info.directives == "object") {
|
||||||
|
directives = this.chrome.appliedTheme.info.directives
|
||||||
}
|
}
|
||||||
if(this.chrome.appliedTheme.info.directives[directive]) {
|
if (directives[directive]) {
|
||||||
return this.chrome.appliedTheme.info.directives[directive].value
|
return this.chrome.appliedTheme.info.directives[directive].value
|
||||||
|
} else if(this.cfg.visual.directives[directive]) {
|
||||||
|
return this.cfg.visual.directives.windowLayout
|
||||||
}else{
|
}else{
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -3367,9 +3394,17 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
async getCurrentArtURL() {
|
async getCurrentArtURL() {
|
||||||
try {
|
try {
|
||||||
|
let artworkSize = 50
|
||||||
|
if (app.getThemeDirective("lcdArtworkSize") != "") {
|
||||||
|
artworkSize = app.getThemeDirective("lcdArtworkSize")
|
||||||
|
}else if(this.cfg.visual.directives.windowLayout == "twopanel") {
|
||||||
|
artworkSize = 70
|
||||||
|
}
|
||||||
this.currentArtUrl = '';
|
this.currentArtUrl = '';
|
||||||
|
this.currentArtUrlRaw = '';
|
||||||
if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url != '') {
|
if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url != '') {
|
||||||
this.currentArtUrl = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50);
|
this.currentArtUrlRaw = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '')
|
||||||
|
this.currentArtUrl = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '').replace('{w}', artworkSize).replace('{h}', artworkSize);
|
||||||
try {
|
try {
|
||||||
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -3378,13 +3413,15 @@ const app = new Vue({
|
||||||
let data = await this.mk.api.v3.music(`/v1/me/library/songs/${this.mk.nowPlayingItem.id}`);
|
let data = await this.mk.api.v3.music(`/v1/me/library/songs/${this.mk.nowPlayingItem.id}`);
|
||||||
data = data.data.data[0];
|
data = data.data.data[0];
|
||||||
if (data != null && data !== "" && data.attributes != null && data.attributes.artwork != null) {
|
if (data != null && data !== "" && data.attributes != null && data.attributes.artwork != null) {
|
||||||
this.currentArtUrl = (data["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50);
|
this.currentArtUrlRaw = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '')
|
||||||
|
this.currentArtUrl = (data["attributes"]["artwork"]["url"] ?? '').replace('{w}', artworkSize).replace('{h}', artworkSize);
|
||||||
ipcRenderer.send('updateRPCImage', this.currentArtUrl ?? '');
|
ipcRenderer.send('updateRPCImage', this.currentArtUrl ?? '');
|
||||||
try {
|
try {
|
||||||
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
this.currentArtUrlRaw = ''
|
||||||
this.currentArtUrl = '';
|
this.currentArtUrl = '';
|
||||||
try {
|
try {
|
||||||
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
|
||||||
|
|
6
src/renderer/js/velocity.min.js
vendored
Normal file
6
src/renderer/js/velocity.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,22 +1,177 @@
|
||||||
#app.twopanel {
|
#app.twopanel {
|
||||||
--chromeHeight1: 42px;
|
--chromeHeight1: 42px;
|
||||||
--chromeHeight2: 55px;
|
--chromeHeight2: 76px;
|
||||||
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
--chromeHeight: calc(var(--chromeHeight1) + var(--chromeHeight2));
|
||||||
|
|
||||||
.app-chrome {
|
.app-chrome {
|
||||||
.app-mainmenu {
|
.app-mainmenu {
|
||||||
|
margin-left: 10px;
|
||||||
width: 88px;
|
width: 88px;
|
||||||
}
|
}
|
||||||
|
|
||||||
height: var(--chromeHeight1);
|
height: var(--chromeHeight1);
|
||||||
|
|
||||||
&.chrome-bottom {
|
&.chrome-bottom {
|
||||||
height: var(--chromeHeight2);
|
height: var(--chromeHeight2);
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.25);
|
box-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25);
|
||||||
.app-chrome--left {
|
|
||||||
padding-left: 32px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar-footer--controls {
|
.app-sidebar-footer--controls {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-chrome.chrome-bottom {
|
||||||
|
.app-playback-controls .actions {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playback-button.play,
|
||||||
|
.playback-button.pause {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
background-color: rgb(200 200 200 / 20%);
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 6px;
|
||||||
|
box-shadow: 0px 0px 0px 2px var(--keyColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-chrome--center {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.app-chrome-playback-controls {
|
||||||
|
display: flex;
|
||||||
|
z-index: 1;
|
||||||
|
// margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-chrome-playback-duration {
|
||||||
|
position: relative;
|
||||||
|
width: 80%;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
.song-progress {
|
||||||
|
@bgColor: transparent;
|
||||||
|
height: 16px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 4px;
|
||||||
|
left: 0px;
|
||||||
|
right: 4px;
|
||||||
|
background: @bgColor;
|
||||||
|
z-index: 0;
|
||||||
|
|
||||||
|
|
||||||
|
.song-duration {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-duration p {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 10px;
|
||||||
|
height: 1.2em;
|
||||||
|
line-height: 1.3em;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0 0 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
> input[type=range] {
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range] {
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
background-color: rgb(200 200 200 / 10%);
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.5);
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 100%;
|
||||||
|
background: var(--keyColor);
|
||||||
|
cursor: default;
|
||||||
|
transition: opacity .10s var(--appleEase), transform .10s var(--appleEase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-chrome--left {
|
||||||
|
width: 30%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.playback-controls {
|
||||||
|
.artwork {
|
||||||
|
width: var(--chromeHeight2);
|
||||||
|
height: var(--chromeHeight2);
|
||||||
|
margin: 0px 6px 0px 0px;
|
||||||
|
box-shadow: unset;
|
||||||
|
border: 0px;
|
||||||
|
|
||||||
|
.mediaitem-artwork,
|
||||||
|
img {
|
||||||
|
border-radius: 0px;
|
||||||
|
box-shadow: unset;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.playback-info {
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: 6px;
|
||||||
|
|
||||||
|
.song-name {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: initial;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-mask-image: linear-gradient(-90deg, transparent 0%, transparent 10%, black 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-artist-album {
|
||||||
|
width: 100%;
|
||||||
|
-webkit-mask-image: linear-gradient(-90deg, transparent 0%, transparent 10%, black 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-type {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-artist-album-content {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-chrome--right {
|
||||||
|
width: 30%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,13 @@
|
||||||
|
.notyf__toast {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notyf-info {
|
||||||
|
background: var(--keyColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.modal-fullscreen {
|
.modal-fullscreen {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
1
src/renderer/themes/groovy/index.less
Normal file
1
src/renderer/themes/groovy/index.less
Normal file
|
@ -0,0 +1 @@
|
||||||
|
//
|
15
src/renderer/themes/groovy/theme.json
Normal file
15
src/renderer/themes/groovy/theme.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "Groovy",
|
||||||
|
"description": "Inspired by Groove Music and Media Player found on Windows",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "ciderapp",
|
||||||
|
"github_repo": "ciderapp/Groovy",
|
||||||
|
"directives": {
|
||||||
|
"windowLayout": {
|
||||||
|
"value": "twopanel"
|
||||||
|
},
|
||||||
|
"lcdArtworkSize": {
|
||||||
|
"value": 70
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +1,5 @@
|
||||||
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
<div class="app-chrome chrome-bottom" v-if="getThemeDirective('windowLayout') == 'twopanel'" :style="{'display': chrome.topChromeVisible ? '' : 'none'}">
|
||||||
<div class="app-chrome--left">
|
<div class="app-chrome--left">
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
|
||||||
@click="mk.shuffleMode = 1"></button>
|
|
||||||
<button class="playback-button--small shuffle active" v-else
|
|
||||||
@click="mk.shuffleMode = 0"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button previous" @click="prevButton()"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
|
||||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button next" @click="skipToNextItem()"></button>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome-item">
|
|
||||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
|
||||||
@click="mk.repeatMode = 1"></button>
|
|
||||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
|
||||||
v-else-if="mk.repeatMode == 1"></button>
|
|
||||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
|
||||||
v-else-if="mk.repeatMode == 2"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="app-chrome--center">
|
|
||||||
<div class="app-chrome-item playback-controls">
|
<div class="app-chrome-item playback-controls">
|
||||||
<template v-if="mkReady()">
|
<template v-if="mkReady()">
|
||||||
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
|
||||||
|
@ -59,21 +33,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="song-progress">
|
|
||||||
<div class="song-duration"
|
|
||||||
style="justify-content: space-between; height: 1px;"
|
|
||||||
:style="[chrome.progresshover ? {'display': 'flex'} : {'display' : 'none'} ]">
|
|
||||||
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
|
||||||
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
|
||||||
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
|
||||||
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
|
|
||||||
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
<template v-if="mk.nowPlayingItem['attributes']['playParams']">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
@ -87,6 +46,50 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome--center">
|
||||||
|
<div class="app-chrome-playback-controls">
|
||||||
|
<div class="app-chrome-item">
|
||||||
|
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||||
|
@click="mk.shuffleMode = 1"></button>
|
||||||
|
<button class="playback-button--small shuffle active" v-else
|
||||||
|
@click="mk.shuffleMode = 0"></button>
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome-item">
|
||||||
|
<button class="playback-button previous" @click="prevButton()"></button>
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome-item">
|
||||||
|
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
||||||
|
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome-item">
|
||||||
|
<button class="playback-button next" @click="skipToNextItem()"></button>
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome-item">
|
||||||
|
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||||
|
@click="mk.repeatMode = 1"></button>
|
||||||
|
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 2"
|
||||||
|
v-else-if="mk.repeatMode == 1"></button>
|
||||||
|
<button class="playback-button--small repeat active" @click="mk.repeatMode = 0"
|
||||||
|
v-else-if="mk.repeatMode == 2"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="app-chrome-playback-duration">
|
||||||
|
<div class="song-progress">
|
||||||
|
<div class="song-duration"
|
||||||
|
style="justify-content: space-between; height: 1px;">
|
||||||
|
<p style="width: auto">{{ convertTime(getSongProgress()) }}</p>
|
||||||
|
<p style="width: auto">{{ convertTime(mk.currentPlaybackDuration) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="range" step="0.01" min="0" :style="progressBarStyle()"
|
||||||
|
@input="playerLCD.desiredDuration = $event.target.value;playerLCD.userInteraction = true"
|
||||||
|
@mouseup="mk.seekToTime($event.target.value);playerLCD.desiredDuration = 0;playerLCD.userInteraction = false"
|
||||||
|
:max="mk.currentPlaybackDuration" :value="getSongProgress()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-chrome--right">
|
<div class="app-chrome--right">
|
||||||
<div class="app-chrome-item volume">
|
<div class="app-chrome-item volume">
|
||||||
|
@ -109,6 +112,11 @@
|
||||||
:class="{'active': drawer.panel == 'lyrics'}"
|
:class="{'active': drawer.panel == 'lyrics'}"
|
||||||
@click="invokeDrawer('lyrics')"></button>
|
@click="invokeDrawer('lyrics')"></button>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<button class="playback-button--small lyrics"
|
||||||
|
:style="{'opacity': 0.3, 'pointer-events': 'none'}"
|
||||||
|
@click="invokeDrawer('lyrics')"></button>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -128,7 +128,11 @@
|
||||||
:class="{'active': drawer.panel == 'lyrics'}"
|
:class="{'active': drawer.panel == 'lyrics'}"
|
||||||
@click="invokeDrawer('lyrics')"></button>
|
@click="invokeDrawer('lyrics')"></button>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<button class="playback-button--small lyrics"
|
||||||
|
:style="{'opacity': 0.3, 'pointer-events': 'none'}"
|
||||||
|
@click="invokeDrawer('lyrics')"></button>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="app-chrome-item full-height" id="window-controls-container" v-if="chrome.windowControlPosition == 'right'">
|
<div class="app-chrome-item full-height" id="window-controls-container" v-if="chrome.windowControlPosition == 'right'">
|
||||||
|
|
|
@ -34,9 +34,31 @@
|
||||||
<script src="./js/bootbox.min.js"></script>
|
<script src="./js/bootbox.min.js"></script>
|
||||||
<script src="./js/notyf.min.js"></script>
|
<script src="./js/notyf.min.js"></script>
|
||||||
<script src="./js/showdown.min.js"></script>
|
<script src="./js/showdown.min.js"></script>
|
||||||
|
<script src="./js/velocity.min.js"></script>
|
||||||
|
<style>
|
||||||
|
#LOADER {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #1E1E1E;
|
||||||
|
z-index: 99999;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#LOADER > svg {
|
||||||
|
width: 128px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body oncontextmenu="return false;" loading="1" platform="<%= env.platform %>">
|
<body oncontextmenu="return false;" loading="1" platform="<%= env.platform %>">
|
||||||
|
<div id="LOADER">
|
||||||
|
<%- include("../assets/cider-round.svg") %>
|
||||||
|
</div>
|
||||||
<div id="app" :class="getAppClasses()">
|
<div id="app" :class="getAppClasses()">
|
||||||
<transition name="fsModeSwitch">
|
<transition name="fsModeSwitch">
|
||||||
<div id="app-main" v-show="appMode == 'player'">
|
<div id="app-main" v-show="appMode == 'player'">
|
||||||
|
@ -47,13 +69,13 @@
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="fsModeSwitch">
|
<transition name="fsModeSwitch">
|
||||||
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
|
||||||
<fullscreen-view :image="currentArtUrl.replace('50x50', '600x600')" :time="lyriccurrenttime"
|
<fullscreen-view :image="currentArtUrlRaw" :time="lyriccurrenttime"
|
||||||
:lyrics="lyrics" :richlyrics="richlyrics"></fullscreen-view>
|
:lyrics="lyrics" :richlyrics="richlyrics"></fullscreen-view>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="fsModeSwitch">
|
<transition name="fsModeSwitch">
|
||||||
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
|
||||||
<mini-view :image="currentArtUrl.replace('50x50', '600x600')" :time="lyriccurrenttime"
|
<mini-view :image="currentArtUrlRaw" :time="lyriccurrenttime"
|
||||||
:lyrics="lyrics" :richlyrics="richlyrics"></mini-view>
|
:lyrics="lyrics" :richlyrics="richlyrics"></mini-view>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -64,6 +86,7 @@
|
||||||
<%- include(env.components[i]); %>
|
<%- include(env.components[i]); %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/x-template"
|
<script type="text/x-template"
|
||||||
id="am-musiccovershelf">
|
id="am-musiccovershelf">
|
||||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
||||||
|
|
|
@ -143,6 +143,17 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
Window Style
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<select class="md-select" v-model="$root.cfg.visual.directives.windowLayout">
|
||||||
|
<option value="default">Cupertino</option>
|
||||||
|
<option value="twopanel">Redmond</option>
|
||||||
|
</select>
|
||||||
|
</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.visual.windowBackgroundStyle')}}
|
{{$root.getLz('settings.option.visual.windowBackgroundStyle')}}
|
||||||
|
|
|
@ -6,12 +6,18 @@
|
||||||
<h1 class="header-text">{{$root.getLz('settings.header.visual.theme.github.page')}}</h1>
|
<h1 class="header-text">{{$root.getLz('settings.header.visual.theme.github.page')}}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto flex-center">
|
<div class="col-auto flex-center">
|
||||||
<select class="md-select" @change="$root.setTheme($root.cfg.visual.theme)" v-model="$root.cfg.visual.theme">
|
<select class="md-select" @change="$root.setTheme($root.cfg.visual.theme)"
|
||||||
|
v-model="$root.cfg.visual.theme">
|
||||||
<option value="default.less">{{$root.getLz('settings.option.visual.theme.default')}}</option>
|
<option value="default.less">{{$root.getLz('settings.option.visual.theme.default')}}</option>
|
||||||
<option value="dark.less">{{$root.getLz('settings.option.visual.theme.dark')}}</option>
|
<option value="dark.less">{{$root.getLz('settings.option.visual.theme.dark')}}</option>
|
||||||
<option v-for="theme in themes" :value="theme.file">{{ theme.name }}</option>
|
<option v-for="theme in themes" :value="theme.file">{{ theme.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-auto flex-center">
|
||||||
|
<button class="md-btn md-btn-small md-btn-block" @click="openThemesFolder()">
|
||||||
|
Open Themes Folder
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="col-auto nopadding flex-center">
|
<div class="col-auto nopadding flex-center">
|
||||||
<button class="md-btn md-btn-small md-btn-block" @click="installThemeURL()">
|
<button class="md-btn md-btn-small md-btn-block" @click="installThemeURL()">
|
||||||
{{$root.getLz('settings.option.visual.theme.github.download')}}
|
{{$root.getLz('settings.option.visual.theme.github.download')}}
|
||||||
|
@ -28,12 +34,14 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col flex-center">
|
<div class="col flex-center">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="repo-name">{{ (repo.description != null) ? repo.description : repo.full_name }}</h4>
|
<h4 class="repo-name">{{ (repo.description != null) ? repo.description :
|
||||||
|
repo.full_name }}</h4>
|
||||||
<div>⭐ {{ repo.stargazers_count }}</div>
|
<div>⭐ {{ repo.stargazers_count }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<span v-if="themesInstalled.includes(repo.full_name)" class="codicon codicon-cloud-download"></span>
|
<span v-if="themesInstalled.includes(repo.full_name.toLowerCase())"
|
||||||
|
class="codicon codicon-cloud-download"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -47,7 +55,8 @@
|
||||||
<div>
|
<div>
|
||||||
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
|
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<div class="svg-icon inline" :style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
<div class="svg-icon inline"
|
||||||
|
:style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
|
||||||
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
|
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
|
||||||
}}</a></div>
|
}}</a></div>
|
||||||
<div>⭐ {{ openRepo.stargazers_count }}</div>
|
<div>⭐ {{ openRepo.stargazers_count }}</div>
|
||||||
|
@ -55,7 +64,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto nopadding flex-center">
|
<div class="col-auto nopadding flex-center">
|
||||||
<button class="md-btn md-btn-primary" @click="installThemeRepo(openRepo)">
|
<button class="md-btn md-btn-primary" @click="installThemeRepo(openRepo)">
|
||||||
<span v-if="!themesInstalled.includes(openRepo.full_name)">{{$root.getLz('action.install')}}</span>
|
<span v-if="!themesInstalled.includes(openRepo.full_name.toLowerCase())">{{$root.getLz('action.install')}}</span>
|
||||||
<span v-else>{{$root.getLz('action.update')}}</span>
|
<span v-else>{{$root.getLz('action.update')}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,16 +106,19 @@
|
||||||
this.themes = ipcRenderer.sendSync("get-themes")
|
this.themes = ipcRenderer.sendSync("get-themes")
|
||||||
this.getRepos();
|
this.getRepos();
|
||||||
this.getInstalledThemes();
|
this.getInstalledThemes();
|
||||||
|
app.checkForThemeUpdates()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openThemesFolder() {
|
||||||
|
ipcRenderer.invoke("open-path", "themes")
|
||||||
|
},
|
||||||
getInstalledThemes() {
|
getInstalledThemes() {
|
||||||
let self = this
|
let self = this
|
||||||
const themes = ipcRenderer.sendSync("get-themes")
|
const themes = ipcRenderer.sendSync("get-themes")
|
||||||
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
|
||||||
themes.forEach(theme => {
|
themes.forEach(theme => {
|
||||||
if (theme.github_repo !== "") {
|
if (theme.github_repo !== "" && typeof theme.commit != "") {
|
||||||
theme.github_repo = theme.github_repo.toLowerCase()
|
self.themesInstalled.push(theme.github_repo.toLowerCase())
|
||||||
self.themesInstalled.push(theme.github_repo)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -182,9 +194,6 @@
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(result => {
|
.then(result => {
|
||||||
let items = JSON.parse(result).items
|
let items = JSON.parse(result).items
|
||||||
items.forEach(repo => {
|
|
||||||
repo.full_name = repo.full_name.toLowerCase()
|
|
||||||
})
|
|
||||||
self.repos = items
|
self.repos = items
|
||||||
})
|
})
|
||||||
.catch(error => console.log('error', error));
|
.catch(error => console.log('error', error));
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"allowJs": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
|
41
winget.json
Normal file
41
winget.json
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"electronVersion": "16.0.7",
|
||||||
|
"electronDownload": {
|
||||||
|
"version": "16.0.7+wvcus",
|
||||||
|
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
|
||||||
|
},
|
||||||
|
"appId": "cider",
|
||||||
|
"afterPack": "./resources/afterPack.js",
|
||||||
|
"afterSign": "./resources/notarize.js",
|
||||||
|
"protocols": [
|
||||||
|
{
|
||||||
|
"name": "Cider",
|
||||||
|
"schemes": [
|
||||||
|
"ame",
|
||||||
|
"cider",
|
||||||
|
"itms",
|
||||||
|
"itmss",
|
||||||
|
"musics",
|
||||||
|
"music"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extends": null,
|
||||||
|
"files": [
|
||||||
|
"./build/**/*",
|
||||||
|
"./src/**/*",
|
||||||
|
"./resources/icons/**/*"
|
||||||
|
],
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": true,
|
||||||
|
"perMachine": false,
|
||||||
|
"deleteAppDataOnUninstall": true,
|
||||||
|
"artifactName": "${productName}-Setup-winget-${version}.${ext}"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": [
|
||||||
|
"nsis"
|
||||||
|
],
|
||||||
|
"icon": "resources/icons/icon.ico"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue