Merge remote-tracking branch 'origin/develop' into develop
|
@ -1,9 +1,11 @@
|
||||||
version: 2.1
|
version: 2.1
|
||||||
|
orbs: # adds orbs to your configuration
|
||||||
|
jira: circleci/jira@1.0.5 # invokes the Jira orb, making its commands accessible
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
working_directory: ~/Cider
|
working_directory: ~/Cider
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:16-browsers
|
- image: circleci/node:16
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
|
@ -12,13 +14,13 @@ jobs:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
name: Restore Yarn Package Cache
|
name: Restore Yarn Package Cache
|
||||||
keys:
|
keys:
|
||||||
- yarn-packages-{{ checksum "cider-yarn.lock" }}
|
- yarn-packages-{{ checksum "yarn.lock" }}
|
||||||
- run:
|
- run:
|
||||||
name: Install Dependencies
|
name: Install Dependencies
|
||||||
command: yarn install --cache-folder ~/.cache/yarn
|
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||||
- save_cache:
|
- save_cache:
|
||||||
name: Save Yarn Package Cache
|
name: Save Yarn Package Cache
|
||||||
key: yarn-packages-{{ checksum "cider-yarn.lock" }}
|
key: yarn-packages-{{ checksum "yarn.lock" }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/yarn
|
- ~/.cache/yarn
|
||||||
- run:
|
- run:
|
||||||
|
@ -32,7 +34,6 @@ jobs:
|
||||||
sudo dpkg --add-architecture i386
|
sudo dpkg --add-architecture i386
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get install -y wine32
|
sudo apt-get install -y wine32
|
||||||
sudo apt-get install -y x11vnc
|
|
||||||
- run:
|
- run:
|
||||||
name: Start X VNC Server
|
name: Start X VNC Server
|
||||||
command: x11vnc -forever -nopw -create
|
command: x11vnc -forever -nopw -create
|
||||||
|
@ -48,9 +49,13 @@ jobs:
|
||||||
- run:
|
- run:
|
||||||
name: Generate Builds (Linux)
|
name: Generate Builds (Linux)
|
||||||
command: yarn dist -l -p never
|
command: yarn dist -l -p never
|
||||||
|
post-steps:
|
||||||
|
- jira/notify
|
||||||
- run:
|
- run:
|
||||||
name: Generate Builds (Windows)
|
name: Generate Builds (Windows)
|
||||||
command: yarn dist -w --x64 -p never
|
command: yarn dist -w --x64 -p never
|
||||||
|
post-steps:
|
||||||
|
- jira/notify
|
||||||
- run:
|
- run:
|
||||||
name: Move Build Files
|
name: Move Build Files
|
||||||
command: |
|
command: |
|
||||||
|
@ -60,7 +65,6 @@ jobs:
|
||||||
mv ~/Cider/dist/*.AppImage ~/Cider/dist/artifacts
|
mv ~/Cider/dist/*.AppImage ~/Cider/dist/artifacts
|
||||||
mv ~/Cider/dist/*.snap ~/Cider/dist/artifacts
|
mv ~/Cider/dist/*.snap ~/Cider/dist/artifacts
|
||||||
mv ~/Cider/dist/*.yml ~/Cider/dist/artifacts
|
mv ~/Cider/dist/*.yml ~/Cider/dist/artifacts
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ~/Cider/dist/artifacts
|
path: ~/Cider/dist/artifacts
|
||||||
|
|
7
.gitignore
vendored
|
@ -318,3 +318,10 @@ keys.sh
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
resources/b64.txt
|
||||||
|
|
||||||
|
|
||||||
|
savedconfig/cider-config.json
|
||||||
|
savedconfig/config.json
|
||||||
|
savedconfig/session.json
|
||||||
|
savedconfig/window-state.json
|
||||||
|
|
|
@ -97,9 +97,9 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"build": {
|
"build": {
|
||||||
"electronVersion": "16.0.7",
|
"electronVersion": "16.0.8",
|
||||||
"electronDownload": {
|
"electronDownload": {
|
||||||
"version": "16.0.7+wvcus",
|
"version": "16.0.8+wvcus",
|
||||||
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
|
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
|
||||||
},
|
},
|
||||||
"appId": "cider",
|
"appId": "cider",
|
||||||
|
|
|
@ -5,13 +5,21 @@ exports.default = function(context) {
|
||||||
if (process.platform !== 'darwin')
|
if (process.platform !== 'darwin')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (fs.existsSync('dist/mac-universal--x64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Electron Framework.sig'))
|
||||||
|
fs.unlinkSync('dist/mac-universal--x64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Electron Framework.sig')
|
||||||
|
if (fs.existsSync('dist/mac-universal--arm64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Electron Framework.sig'))
|
||||||
|
fs.unlinkSync('dist/mac-universal--arm64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Electron Framework.sig')
|
||||||
console.log('Castlabs-evs update start')
|
console.log('Castlabs-evs update start')
|
||||||
execSync('python3 -m pip install --upgrade castlabs-evs')
|
execSync('python3 -m pip install --upgrade castlabs-evs')
|
||||||
console.log('Castlabs-evs update complete')
|
console.log('Castlabs-evs update complete')
|
||||||
|
|
||||||
|
// xcode 13
|
||||||
|
if (fs.existsSync('dist/mac-universal--x64') && fs.existsSync('dist/mac-universal--arm64'))
|
||||||
|
execSync("cp 'dist/mac-universal--x64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib' 'dist/mac-universal--arm64/Cider.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib'",{stdio: 'inherit'})
|
||||||
|
|
||||||
console.log('VMP signing start')
|
console.log('VMP signing start')
|
||||||
|
if (fs.existsSync('dist/mac-universal'))
|
||||||
|
execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac-universal',{stdio: 'inherit'})
|
||||||
if (fs.existsSync('dist/mac'))
|
if (fs.existsSync('dist/mac'))
|
||||||
execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac',{stdio: 'inherit'})
|
execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac',{stdio: 'inherit'})
|
||||||
if (fs.existsSync('dist/mac-arm64'))
|
if (fs.existsSync('dist/mac-arm64'))
|
||||||
|
|
399
resources/macPackager.js
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const bluebird_lst_1 = require("bluebird-lst");
|
||||||
|
const builder_util_1 = require("builder-util");
|
||||||
|
const electron_osx_sign_1 = require("electron-osx-sign");
|
||||||
|
const promises_1 = require("fs/promises");
|
||||||
|
const lazy_val_1 = require("lazy-val");
|
||||||
|
const path = require("path");
|
||||||
|
const fs_1 = require("builder-util/out/fs");
|
||||||
|
const promise_1 = require("builder-util/out/promise");
|
||||||
|
const appInfo_1 = require("./appInfo");
|
||||||
|
const macCodeSign_1 = require("./codeSign/macCodeSign");
|
||||||
|
const core_1 = require("./core");
|
||||||
|
const platformPackager_1 = require("./platformPackager");
|
||||||
|
const ArchiveTarget_1 = require("./targets/ArchiveTarget");
|
||||||
|
const pkg_1 = require("./targets/pkg");
|
||||||
|
const targetFactory_1 = require("./targets/targetFactory");
|
||||||
|
const macosVersion_1 = require("./util/macosVersion");
|
||||||
|
const pathManager_1 = require("./util/pathManager");
|
||||||
|
const fs = require("fs/promises");
|
||||||
|
class MacPackager extends platformPackager_1.PlatformPackager {
|
||||||
|
constructor(info) {
|
||||||
|
super(info, core_1.Platform.MAC);
|
||||||
|
this.codeSigningInfo = new lazy_val_1.Lazy(() => {
|
||||||
|
const cscLink = this.getCscLink();
|
||||||
|
if (cscLink == null || process.platform !== "darwin") {
|
||||||
|
return Promise.resolve({ keychainFile: process.env.CSC_KEYCHAIN || null });
|
||||||
|
}
|
||||||
|
return macCodeSign_1.createKeychain({
|
||||||
|
tmpDir: this.info.tempDirManager,
|
||||||
|
cscLink,
|
||||||
|
cscKeyPassword: this.getCscPassword(),
|
||||||
|
cscILink: platformPackager_1.chooseNotNull(this.platformSpecificBuildOptions.cscInstallerLink, process.env.CSC_INSTALLER_LINK),
|
||||||
|
cscIKeyPassword: platformPackager_1.chooseNotNull(this.platformSpecificBuildOptions.cscInstallerKeyPassword, process.env.CSC_INSTALLER_KEY_PASSWORD),
|
||||||
|
currentDir: this.projectDir,
|
||||||
|
}).then(result => {
|
||||||
|
const keychainFile = result.keychainFile;
|
||||||
|
if (keychainFile != null) {
|
||||||
|
this.info.disposeOnBuildFinish(() => macCodeSign_1.removeKeychain(keychainFile));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this._iconPath = new lazy_val_1.Lazy(() => this.getOrConvertIcon("icns"));
|
||||||
|
}
|
||||||
|
get defaultTarget() {
|
||||||
|
return this.info.framework.macOsDefaultTargets;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
prepareAppInfo(appInfo) {
|
||||||
|
return new appInfo_1.AppInfo(this.info, this.platformSpecificBuildOptions.bundleVersion, this.platformSpecificBuildOptions);
|
||||||
|
}
|
||||||
|
async getIconPath() {
|
||||||
|
return this._iconPath.value;
|
||||||
|
}
|
||||||
|
createTargets(targets, mapper) {
|
||||||
|
for (const name of targets) {
|
||||||
|
switch (name) {
|
||||||
|
case core_1.DIR_TARGET:
|
||||||
|
break;
|
||||||
|
case "dmg": {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const { DmgTarget } = require("dmg-builder");
|
||||||
|
mapper(name, outDir => new DmgTarget(this, outDir));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "zip":
|
||||||
|
// https://github.com/electron-userland/electron-builder/issues/2313
|
||||||
|
mapper(name, outDir => new ArchiveTarget_1.ArchiveTarget(name, outDir, this, true));
|
||||||
|
break;
|
||||||
|
case "pkg":
|
||||||
|
mapper(name, outDir => new pkg_1.PkgTarget(this, outDir));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mapper(name, outDir => (name === "mas" || name === "mas-dev" ? new targetFactory_1.NoOpTarget(name) : targetFactory_1.createCommonTarget(name, outDir, this)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async doPack(outDir, appOutDir, platformName, arch, platformSpecificBuildOptions, targets) {
|
||||||
|
switch (arch) {
|
||||||
|
default: {
|
||||||
|
return super.doPack(outDir, appOutDir, platformName, arch, platformSpecificBuildOptions, targets);
|
||||||
|
}
|
||||||
|
case builder_util_1.Arch.universal: {
|
||||||
|
const x64Arch = builder_util_1.Arch.x64;
|
||||||
|
const x64AppOutDir = appOutDir + "--" + builder_util_1.Arch[x64Arch];
|
||||||
|
await super.doPack(outDir, x64AppOutDir, platformName, x64Arch, platformSpecificBuildOptions, targets, false, true);
|
||||||
|
const arm64Arch = builder_util_1.Arch.arm64;
|
||||||
|
const arm64AppOutPath = appOutDir + "--" + builder_util_1.Arch[arm64Arch];
|
||||||
|
await super.doPack(outDir, arm64AppOutPath, platformName, arm64Arch, platformSpecificBuildOptions, targets, false, true);
|
||||||
|
const framework = this.info.framework;
|
||||||
|
builder_util_1.log.info({
|
||||||
|
platform: platformName,
|
||||||
|
arch: builder_util_1.Arch[arch],
|
||||||
|
[`${framework.name}`]: framework.version,
|
||||||
|
appOutDir: builder_util_1.log.filePath(appOutDir),
|
||||||
|
}, `packaging`);
|
||||||
|
const appFile = `${this.appInfo.productFilename}.app`;
|
||||||
|
const { makeUniversalApp } = require("@electron/universal");
|
||||||
|
await makeUniversalApp({
|
||||||
|
x64AppPath: path.join(x64AppOutDir, appFile),
|
||||||
|
arm64AppPath: path.join(arm64AppOutPath, appFile),
|
||||||
|
outAppPath: path.join(appOutDir, appFile),
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
await fs.rm(x64AppOutDir, { recursive: true, force: true });
|
||||||
|
await fs.rm(arm64AppOutPath, { recursive: true, force: true });
|
||||||
|
const packContext = {
|
||||||
|
appOutDir,
|
||||||
|
outDir,
|
||||||
|
arch,
|
||||||
|
targets,
|
||||||
|
packager: this,
|
||||||
|
electronPlatformName: platformName,
|
||||||
|
}
|
||||||
|
await this.info.afterPack(packContext)
|
||||||
|
if (framework.afterPack != null) {
|
||||||
|
await framework.afterPack(packContext)
|
||||||
|
}
|
||||||
|
await this.doSignAfterPack(outDir, appOutDir, platformName, arch, platformSpecificBuildOptions, targets);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async pack(outDir, arch, targets, taskManager) {
|
||||||
|
let nonMasPromise = null;
|
||||||
|
const hasMas = targets.length !== 0 && targets.some(it => it.name === "mas" || it.name === "mas-dev");
|
||||||
|
const prepackaged = this.packagerOptions.prepackaged;
|
||||||
|
if (!hasMas || targets.length > 1) {
|
||||||
|
const appPath = prepackaged == null ? path.join(this.computeAppOutDir(outDir, arch), `${this.appInfo.productFilename}.app`) : prepackaged;
|
||||||
|
nonMasPromise = (prepackaged
|
||||||
|
? Promise.resolve()
|
||||||
|
: this.doPack(outDir, path.dirname(appPath), this.platform.nodeName, arch, this.platformSpecificBuildOptions, targets)).then(() => this.packageInDistributableFormat(appPath, arch, targets, taskManager));
|
||||||
|
}
|
||||||
|
for (const target of targets) {
|
||||||
|
const targetName = target.name;
|
||||||
|
if (!(targetName === "mas" || targetName === "mas-dev")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const masBuildOptions = builder_util_1.deepAssign({}, this.platformSpecificBuildOptions, this.config.mas);
|
||||||
|
if (targetName === "mas-dev") {
|
||||||
|
builder_util_1.deepAssign(masBuildOptions, this.config.masDev, {
|
||||||
|
type: "development",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const targetOutDir = path.join(outDir, `${targetName}${builder_util_1.getArchSuffix(arch)}`);
|
||||||
|
if (prepackaged == null) {
|
||||||
|
await this.doPack(outDir, targetOutDir, "mas", arch, masBuildOptions, [target]);
|
||||||
|
await this.sign(path.join(targetOutDir, `${this.appInfo.productFilename}.app`), targetOutDir, masBuildOptions, arch);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await this.sign(prepackaged, targetOutDir, masBuildOptions, arch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nonMasPromise != null) {
|
||||||
|
await nonMasPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async sign(appPath, outDir, masOptions, arch) {
|
||||||
|
if (!macCodeSign_1.isSignAllowed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isMas = masOptions != null;
|
||||||
|
const options = masOptions == null ? this.platformSpecificBuildOptions : masOptions;
|
||||||
|
const qualifier = options.identity;
|
||||||
|
if (!isMas && qualifier === null) {
|
||||||
|
if (this.forceCodeSigning) {
|
||||||
|
throw new builder_util_1.InvalidConfigurationError("identity explicitly is set to null, but forceCodeSigning is set to true");
|
||||||
|
}
|
||||||
|
builder_util_1.log.info({ reason: "identity explicitly is set to null" }, "skipped macOS code signing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keychainFile = (await this.codeSigningInfo.value).keychainFile;
|
||||||
|
const explicitType = options.type;
|
||||||
|
const type = explicitType || "distribution";
|
||||||
|
const isDevelopment = type === "development";
|
||||||
|
const certificateTypes = getCertificateTypes(isMas, isDevelopment);
|
||||||
|
let identity = null;
|
||||||
|
for (const certificateType of certificateTypes) {
|
||||||
|
identity = await macCodeSign_1.findIdentity(certificateType, qualifier, keychainFile);
|
||||||
|
if (identity != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (identity == null) {
|
||||||
|
if (!isMas && !isDevelopment && explicitType !== "distribution") {
|
||||||
|
identity = await macCodeSign_1.findIdentity("Mac Developer", qualifier, keychainFile);
|
||||||
|
if (identity != null) {
|
||||||
|
builder_util_1.log.warn("Mac Developer is used to sign app — it is only for development and testing, not for production");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (identity == null) {
|
||||||
|
await macCodeSign_1.reportError(isMas, certificateTypes, qualifier, keychainFile, this.forceCodeSigning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!macosVersion_1.isMacOsHighSierra()) {
|
||||||
|
throw new builder_util_1.InvalidConfigurationError("macOS High Sierra 10.13.6 is required to sign");
|
||||||
|
}
|
||||||
|
let filter = options.signIgnore;
|
||||||
|
if (Array.isArray(filter)) {
|
||||||
|
if (filter.length == 0) {
|
||||||
|
filter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (filter != null) {
|
||||||
|
filter = filter.length === 0 ? null : [filter];
|
||||||
|
}
|
||||||
|
const filterRe = filter == null ? null : filter.map(it => new RegExp(it));
|
||||||
|
let binaries = options.binaries || undefined;
|
||||||
|
if (binaries) {
|
||||||
|
// Accept absolute paths for external binaries, else resolve relative paths from the artifact's app Contents path.
|
||||||
|
const userDefinedBinaries = await Promise.all(binaries.map(async (destination) => {
|
||||||
|
if (await fs_1.statOrNull(destination)) {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
return path.resolve(appPath, destination);
|
||||||
|
}));
|
||||||
|
// Insert at front to prioritize signing. We still sort by depth next
|
||||||
|
binaries = userDefinedBinaries.concat(binaries);
|
||||||
|
builder_util_1.log.info("Signing addtional user-defined binaries: " + JSON.stringify(userDefinedBinaries, null, 1));
|
||||||
|
}
|
||||||
|
const signOptions = {
|
||||||
|
"identity-validation": false,
|
||||||
|
// https://github.com/electron-userland/electron-builder/issues/1699
|
||||||
|
// kext are signed by the chipset manufacturers. You need a special certificate (only available on request) from Apple to be able to sign kext.
|
||||||
|
ignore: (file) => {
|
||||||
|
if (filterRe != null) {
|
||||||
|
for (const regExp of filterRe) {
|
||||||
|
if (regExp.test(file)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (file.endsWith(".kext") ||
|
||||||
|
file.startsWith("/Contents/PlugIns", appPath.length) ||
|
||||||
|
file.includes("/node_modules/puppeteer/.local-chromium") ||
|
||||||
|
file.includes("/node_modules/playwright-firefox/.local-browsers") ||
|
||||||
|
file.includes("/node_modules/playwright/.local-browsers"));
|
||||||
|
/* Those are browser automating modules, browser (chromium, nightly) cannot be signed
|
||||||
|
https://github.com/electron-userland/electron-builder/issues/2010
|
||||||
|
https://github.com/electron-userland/electron-builder/issues/5383
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
identity: identity,
|
||||||
|
type,
|
||||||
|
platform: isMas ? "mas" : "darwin",
|
||||||
|
version: this.config.electronVersion,
|
||||||
|
app: appPath,
|
||||||
|
keychain: keychainFile || undefined,
|
||||||
|
binaries,
|
||||||
|
timestamp: isMas ? masOptions === null || masOptions === void 0 ? void 0 : masOptions.timestamp : options.timestamp,
|
||||||
|
requirements: isMas || this.platformSpecificBuildOptions.requirements == null ? undefined : await this.getResource(this.platformSpecificBuildOptions.requirements),
|
||||||
|
// https://github.com/electron-userland/electron-osx-sign/issues/196
|
||||||
|
// will fail on 10.14.5+ because a signed but unnotarized app is also rejected.
|
||||||
|
"gatekeeper-assess": options.gatekeeperAssess === true,
|
||||||
|
// https://github.com/electron-userland/electron-builder/issues/1480
|
||||||
|
"strict-verify": options.strictVerify,
|
||||||
|
hardenedRuntime: isMas ? masOptions && masOptions.hardenedRuntime === true : options.hardenedRuntime !== false,
|
||||||
|
};
|
||||||
|
await this.adjustSignOptions(signOptions, masOptions);
|
||||||
|
builder_util_1.log.info({
|
||||||
|
file: builder_util_1.log.filePath(appPath),
|
||||||
|
identityName: identity.name,
|
||||||
|
identityHash: identity.hash,
|
||||||
|
provisioningProfile: signOptions["provisioning-profile"] || "none",
|
||||||
|
}, "signing");
|
||||||
|
await this.doSign(signOptions);
|
||||||
|
// https://github.com/electron-userland/electron-builder/issues/1196#issuecomment-312310209
|
||||||
|
if (masOptions != null && !isDevelopment) {
|
||||||
|
const certType = isDevelopment ? "Mac Developer" : "3rd Party Mac Developer Installer";
|
||||||
|
const masInstallerIdentity = await macCodeSign_1.findIdentity(certType, masOptions.identity, keychainFile);
|
||||||
|
if (masInstallerIdentity == null) {
|
||||||
|
throw new builder_util_1.InvalidConfigurationError(`Cannot find valid "${certType}" identity to sign MAS installer, please see https://electron.build/code-signing`);
|
||||||
|
}
|
||||||
|
// mas uploaded to AppStore, so, use "-" instead of space for name
|
||||||
|
const artifactName = this.expandArtifactNamePattern(masOptions, "pkg", arch);
|
||||||
|
const artifactPath = path.join(outDir, artifactName);
|
||||||
|
await this.doFlat(appPath, artifactPath, masInstallerIdentity, keychainFile);
|
||||||
|
await this.dispatchArtifactCreated(artifactPath, null, builder_util_1.Arch.x64, this.computeSafeArtifactName(artifactName, "pkg", arch, true, this.platformSpecificBuildOptions.defaultArch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async adjustSignOptions(signOptions, masOptions) {
|
||||||
|
const resourceList = await this.resourceList;
|
||||||
|
const customSignOptions = masOptions || this.platformSpecificBuildOptions;
|
||||||
|
const entitlementsSuffix = masOptions == null ? "mac" : "mas";
|
||||||
|
let entitlements = customSignOptions.entitlements;
|
||||||
|
if (entitlements == null) {
|
||||||
|
const p = `entitlements.${entitlementsSuffix}.plist`;
|
||||||
|
if (resourceList.includes(p)) {
|
||||||
|
entitlements = path.join(this.info.buildResourcesDir, p);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entitlements = pathManager_1.getTemplatePath("entitlements.mac.plist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signOptions.entitlements = entitlements;
|
||||||
|
let entitlementsInherit = customSignOptions.entitlementsInherit;
|
||||||
|
if (entitlementsInherit == null) {
|
||||||
|
const p = `entitlements.${entitlementsSuffix}.inherit.plist`;
|
||||||
|
if (resourceList.includes(p)) {
|
||||||
|
entitlementsInherit = path.join(this.info.buildResourcesDir, p);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entitlementsInherit = pathManager_1.getTemplatePath("entitlements.mac.plist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signOptions["entitlements-inherit"] = entitlementsInherit;
|
||||||
|
if (customSignOptions.provisioningProfile != null) {
|
||||||
|
signOptions["provisioning-profile"] = customSignOptions.provisioningProfile;
|
||||||
|
}
|
||||||
|
signOptions["entitlements-loginhelper"] = customSignOptions.entitlementsLoginHelper;
|
||||||
|
}
|
||||||
|
//noinspection JSMethodCanBeStatic
|
||||||
|
async doSign(opts) {
|
||||||
|
return electron_osx_sign_1.signAsync(opts);
|
||||||
|
}
|
||||||
|
//noinspection JSMethodCanBeStatic
|
||||||
|
async doFlat(appPath, outFile, identity, keychain) {
|
||||||
|
// productbuild doesn't created directory for out file
|
||||||
|
await promises_1.mkdir(path.dirname(outFile), { recursive: true });
|
||||||
|
const args = pkg_1.prepareProductBuildArgs(identity, keychain);
|
||||||
|
args.push("--component", appPath, "/Applications");
|
||||||
|
args.push(outFile);
|
||||||
|
return await builder_util_1.exec("productbuild", args);
|
||||||
|
}
|
||||||
|
getElectronSrcDir(dist) {
|
||||||
|
return path.resolve(this.projectDir, dist, this.info.framework.distMacOsAppName);
|
||||||
|
}
|
||||||
|
getElectronDestinationDir(appOutDir) {
|
||||||
|
return path.join(appOutDir, this.info.framework.distMacOsAppName);
|
||||||
|
}
|
||||||
|
// todo fileAssociations
|
||||||
|
async applyCommonInfo(appPlist, contentsPath) {
|
||||||
|
const appInfo = this.appInfo;
|
||||||
|
const appFilename = appInfo.productFilename;
|
||||||
|
// https://github.com/electron-userland/electron-builder/issues/1278
|
||||||
|
appPlist.CFBundleExecutable = appFilename.endsWith(" Helper") ? appFilename.substring(0, appFilename.length - " Helper".length) : appFilename;
|
||||||
|
const icon = await this.getIconPath();
|
||||||
|
if (icon != null) {
|
||||||
|
const oldIcon = appPlist.CFBundleIconFile;
|
||||||
|
const resourcesPath = path.join(contentsPath, "Resources");
|
||||||
|
if (oldIcon != null) {
|
||||||
|
await fs_1.unlinkIfExists(path.join(resourcesPath, oldIcon));
|
||||||
|
}
|
||||||
|
const iconFileName = "icon.icns";
|
||||||
|
appPlist.CFBundleIconFile = iconFileName;
|
||||||
|
await fs_1.copyFile(icon, path.join(resourcesPath, iconFileName));
|
||||||
|
}
|
||||||
|
appPlist.CFBundleName = appInfo.productName;
|
||||||
|
appPlist.CFBundleDisplayName = appInfo.productName;
|
||||||
|
const minimumSystemVersion = this.platformSpecificBuildOptions.minimumSystemVersion;
|
||||||
|
if (minimumSystemVersion != null) {
|
||||||
|
appPlist.LSMinimumSystemVersion = minimumSystemVersion;
|
||||||
|
}
|
||||||
|
appPlist.CFBundleIdentifier = appInfo.macBundleIdentifier;
|
||||||
|
appPlist.CFBundleShortVersionString = this.platformSpecificBuildOptions.bundleShortVersion || appInfo.version;
|
||||||
|
appPlist.CFBundleVersion = appInfo.buildVersion;
|
||||||
|
builder_util_1.use(this.platformSpecificBuildOptions.category || this.config.category, it => (appPlist.LSApplicationCategoryType = it));
|
||||||
|
appPlist.NSHumanReadableCopyright = appInfo.copyright;
|
||||||
|
if (this.platformSpecificBuildOptions.darkModeSupport) {
|
||||||
|
appPlist.NSRequiresAquaSystemAppearance = false;
|
||||||
|
}
|
||||||
|
const extendInfo = this.platformSpecificBuildOptions.extendInfo;
|
||||||
|
if (extendInfo != null) {
|
||||||
|
Object.assign(appPlist, extendInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async signApp(packContext, isAsar) {
|
||||||
|
const appFileName = `${this.appInfo.productFilename}.app`;
|
||||||
|
await bluebird_lst_1.default.map(promises_1.readdir(packContext.appOutDir), (file) => {
|
||||||
|
if (file === appFileName) {
|
||||||
|
return this.sign(path.join(packContext.appOutDir, file), null, null, null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!isAsar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const outResourcesDir = path.join(packContext.appOutDir, "resources", "app.asar.unpacked");
|
||||||
|
await bluebird_lst_1.default.map(promise_1.orIfFileNotExist(promises_1.readdir(outResourcesDir), []), (file) => {
|
||||||
|
if (file.endsWith(".app")) {
|
||||||
|
return this.sign(path.join(outResourcesDir, file), null, null, null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = MacPackager;
|
||||||
|
function getCertificateTypes(isMas, isDevelopment) {
|
||||||
|
if (isDevelopment) {
|
||||||
|
return isMas ? ["Mac Developer", "Apple Development"] : ["Developer ID Application"];
|
||||||
|
}
|
||||||
|
return isMas ? ["Apple Distribution"] : ["Developer ID Application"];
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=macPackager.js.map
|
|
@ -81,3 +81,7 @@ Update 08/02/2022 10:20 UTC
|
||||||
* `settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility`: Added for `en_US`.
|
* `settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility`: Added for `en_US`.
|
||||||
* `term.requestError`: Added for `en_US`.
|
* `term.requestError`: Added for `en_US`.
|
||||||
* `term.song.link.generate`: Added for `en_US`.
|
* `term.song.link.generate`: Added for `en_US`.
|
||||||
|
|
||||||
|
Update 10/02/2022 05:58 UTC
|
||||||
|
|
||||||
|
* `term.sortBy.dateAdded`: Added for `en_US`.
|
||||||
|
|
357
src/i18n/cz_CZ.jsonc
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
{ // Base File
|
||||||
|
// i18n Info
|
||||||
|
"i18n.languageName": "Čeština (CZ)", // name of language in native language
|
||||||
|
"i18n.languageNameEnglish": "Czech (CZ)", // name of language in English
|
||||||
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
|
"i18n.authors": "@matuskoOk", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
|
// App info
|
||||||
|
"app.name": "Cider",
|
||||||
|
|
||||||
|
"date.format": "${d} ${m}, ${y}",
|
||||||
|
|
||||||
|
// Dialogs
|
||||||
|
"dialog.cancel": "Zrušit",
|
||||||
|
"dialog.ok": "OK",
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
"notification.updatingLibrarySongs": "Aktualizace skladeb v knihovně...",
|
||||||
|
"notification.updatingLibraryAlbums": "Aktualizace alb knihovny...",
|
||||||
|
"notification.updatingLibraryArtists": "Aktualizace umělců knihovny...",
|
||||||
|
|
||||||
|
// Terms
|
||||||
|
"term.appleInc": "Apple Inc.",
|
||||||
|
"term.appleMusic": "Apple Music",
|
||||||
|
"term.applePodcasts": "Apple Podcasts",
|
||||||
|
"term.itunes": "iTunes",
|
||||||
|
"term.github": "GitHub",
|
||||||
|
"term.discord": "Discord",
|
||||||
|
"term.learnMore": "Zjistěte více",
|
||||||
|
"term.accountSettings": "Nastavení účtu",
|
||||||
|
"term.logout": "Odhlásit se",
|
||||||
|
"term.login": "Přihlásit se",
|
||||||
|
"term.about": "About",
|
||||||
|
"term.privateSession": "Soukromá relace",
|
||||||
|
"term.queue": "Fronta",
|
||||||
|
"term.history": "Historie",
|
||||||
|
"term.search": "Vyhledávání",
|
||||||
|
"term.library": "Knihovna",
|
||||||
|
"term.listenNow": "Poslouchejte hned",
|
||||||
|
"term.browse": "Procházet",
|
||||||
|
"term.radio": "Rádio",
|
||||||
|
"term.recentlyAdded": "Nedávno přidané",
|
||||||
|
"term.songs": "Písně",
|
||||||
|
"term.albums": "Alba",
|
||||||
|
"term.artists": "Umělci",
|
||||||
|
"term.podcasts": "Podcasty",
|
||||||
|
"term.playlists": "Playlists",
|
||||||
|
"term.playlist": "Playlist",
|
||||||
|
"term.newPlaylist": "Nový seznam playlistu",
|
||||||
|
"term.newPlaylistFolder": "Nová složka playlistov",
|
||||||
|
"term.createNewPlaylist": "Vytvořit nový seznam playlistov",
|
||||||
|
"term.createNewPlaylistFolder": "Vytvořit nový seznam playlist složka",
|
||||||
|
"term.deletePlaylist": "Opravdu chcete tento playlist smazat?",
|
||||||
|
"term.play": "Play",
|
||||||
|
"term.pause": "Pause",
|
||||||
|
"term.previous": "Předchozí",
|
||||||
|
"term.next": "Další",
|
||||||
|
"term.shuffle": "Zamíchat",
|
||||||
|
"term.repeat": "Repeat",
|
||||||
|
"term.volume": "Hlasitosť",
|
||||||
|
"term.mute": "Mute",
|
||||||
|
"term.unmute": "Ztlumit",
|
||||||
|
"term.share": "Zdílet",
|
||||||
|
"term.share.success": "Zkopírováno do clipboard",
|
||||||
|
"term.settings": "Nastavení",
|
||||||
|
"term.seeAll": "Vidět vše",
|
||||||
|
"term.sortBy": "Seřazeno podle",
|
||||||
|
"term.sortBy.album": "Album",
|
||||||
|
"term.sortBy.artist": "Umělec",
|
||||||
|
"term.sortBy.name": "Název",
|
||||||
|
"term.sortBy.genre": "Žánr",
|
||||||
|
"term.sortBy.releaseDate": "Datum vydání",
|
||||||
|
"term.sortBy.duration": "Doba trvání",
|
||||||
|
"term.sortOrder": "A-Z",
|
||||||
|
"term.sortOrder.ascending": "Vzestupně",
|
||||||
|
"term.sortOrder.descending": "Klesající",
|
||||||
|
"term.viewAs": "Zobrazit jako",
|
||||||
|
"term.viewAs.coverArt": "Obálka Art",
|
||||||
|
"term.viewAs.list": "Seznam",
|
||||||
|
"term.size": "Velikost",
|
||||||
|
"term.size.normal": "Normální",
|
||||||
|
"term.size.compact": "Kompaktní",
|
||||||
|
"term.enable": "Zapnout",
|
||||||
|
"term.disable": "Vypnout",
|
||||||
|
"term.enabled": "Zapnuto",
|
||||||
|
"term.disabled": "Vypnuto",
|
||||||
|
"term.connect": "Připojit",
|
||||||
|
"term.connecting": "Připojování",
|
||||||
|
"term.disconnect": "Odpojit",
|
||||||
|
"term.authed": "Ověřeno",
|
||||||
|
"term.confirm": "Potvrdit?",
|
||||||
|
"term.more": "Více",
|
||||||
|
"term.less": "Méně",
|
||||||
|
"term.showMore": "Zobrazit více",
|
||||||
|
"term.showLess": "Ukaž méně",
|
||||||
|
"term.topSongs": "Nejlepší skladby",
|
||||||
|
"term.latestReleases": "Nejnovější verze",
|
||||||
|
"term.time.added": "Přidané",
|
||||||
|
"term.time.released": "Vydáno",
|
||||||
|
"term.time.updated": "Aktualizováno",
|
||||||
|
"term.time.hours": "hodin",
|
||||||
|
"term.time.hour": "hodina",
|
||||||
|
"term.time.minutes": "minut",
|
||||||
|
"term.time.minute": "minuta",
|
||||||
|
"term.time.seconds": "sekundy",
|
||||||
|
"term.time.second": "sekunda",
|
||||||
|
"term.fullscreenView": "Zobrazení na celou obrazovku",
|
||||||
|
"term.defaultView": "Výchozí zobrazení",
|
||||||
|
"term.audioSettings": "Nastavení zvuku",
|
||||||
|
"term.clearAll": "Vymazat vše",
|
||||||
|
"term.recentStations": "Nedávné stanice",
|
||||||
|
"term.language": "Jazyk",
|
||||||
|
"term.funLanguages": "Zábava",
|
||||||
|
"term.noLyrics": "Načítání... / Text nenalezen./ Instrumentální.",
|
||||||
|
"term.copyright": "Autorská práva",
|
||||||
|
"term.rightsReserved": "Všechna práva vyhrazena.",
|
||||||
|
"term.sponsor": "Sponzorujte tento projekt",
|
||||||
|
"term.ciderTeam": "Cider Tým",
|
||||||
|
"term.developer": "Vývojář",
|
||||||
|
"term.socialTeam": "Sociální tým",
|
||||||
|
"term.socials": "Socials",
|
||||||
|
"term.contributors": "Přispěvatelé",
|
||||||
|
"term.equalizer": "Ekvalizér",
|
||||||
|
"term.reset": "Resetovat",
|
||||||
|
"term.tracks": "tracks", // Assume x amount of tracks. e.g. 50 tracks
|
||||||
|
"term.videos": "Videa",
|
||||||
|
"term.menu": "Menu",
|
||||||
|
"term.check": "Zkontrolovat",
|
||||||
|
"term.aboutArtist": "O {{artistName}}", // e.g. 'About Doja Cat'
|
||||||
|
"term.topResult": "Nejlepší výsledek", // Search Results
|
||||||
|
"term.sharedPlaylists": "Sdílený Playlists", // Search Results
|
||||||
|
"term.people": "Lidé", // Search Results
|
||||||
|
"term.newpreset.name": "Název nové předvolby EQ", // Equalizer Preset
|
||||||
|
"term.addedpreset": "Přidána předvolba",
|
||||||
|
"term.deletepreset.warn": "Opravdu chcete tuto předvolbu smazat?",
|
||||||
|
"term.deletedpreset": "Předvolba byla odstraněna",
|
||||||
|
"term.musicVideos": "Hudební videa", // Search page friendlyTypes
|
||||||
|
"term.stations": "Stanice",
|
||||||
|
"term.curators": "Kurátoři",
|
||||||
|
"term.appleCurators": "Apple Curators",
|
||||||
|
"term.radioShows": "Rozhlasové pořady",
|
||||||
|
"term.recordLabels": "Nahrávací štítky",
|
||||||
|
"term.videoExtras": "Video Extra",
|
||||||
|
"term.top": "Top",
|
||||||
|
|
||||||
|
// Home
|
||||||
|
"home.title": "Domů",
|
||||||
|
"home.recentlyPlayed": "Nedávno hrané",
|
||||||
|
"home.recentlyAdded": "Nedávno přidané",
|
||||||
|
"home.artistsFeed": "Váš kanál umělců",
|
||||||
|
"home.artistsFeed.noArtist": "Nejprve sledujte některé umělce a jejich nejnovější verze budou zde",
|
||||||
|
"home.madeForYou": "Uděláno pro tebe",
|
||||||
|
"home.friendsListeningTo": "Přátelé Poslouchají",
|
||||||
|
"home.followedArtists": "Sledované umělce",
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
"error.appleMusicSubRequired": "Apple Music vyžaduje předplatné.",
|
||||||
|
"error.connectionError": "Došlo k problému s připojením k Apple Music.",
|
||||||
|
"error.noResults": "Žádné výsledky.",
|
||||||
|
"error.noResults.description": "Zkuste nové vyhledávání.",
|
||||||
|
|
||||||
|
// Podcasts
|
||||||
|
"podcast.followOnCider": "Sledujte Na Cider",
|
||||||
|
"podcast.followedOnCider": "Sledujete Na Cider",
|
||||||
|
"podcast.subscribeOnItunes": "Předplatit na iTunes",
|
||||||
|
"podcast.subscribedOnItunes": "Předplaceno na iTunes",
|
||||||
|
"podcast.itunesStore": "iTunes Store",
|
||||||
|
"podcast.episodes": "Epizody",
|
||||||
|
"podcast.playEpisode": "Přehrát epizodu",
|
||||||
|
"podcast.website": "Webová stránka podcastun ",
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
"action.addToLibrary": "Přidat do knihovny",
|
||||||
|
"action.addToLibrary.success": "Přidáno do knihovny",
|
||||||
|
"action.addToLibrary.error": "Chyba při přidávání do knihovny",
|
||||||
|
"action.removeFromLibrary": "Odebrat z knihovny",
|
||||||
|
"action.removeFromLibrary.success": "Odebráno z knihovny",
|
||||||
|
"action.addToQueue": "Přidat do fronty",
|
||||||
|
"action.addToQueue.success": "Přidáno do fronty",
|
||||||
|
"action.addToQueue.error": "Chyba při přidávání do fronty",
|
||||||
|
"action.removeFromQueue": "Odebrat z fronty",
|
||||||
|
"action.removeFromQueue.success": "Odebráno z fronty",
|
||||||
|
"action.removeFromQueue.error": "Chyba při odstraňování z fronty",
|
||||||
|
"action.createPlaylist": "Vytvoř nový Playlist",
|
||||||
|
"action.addToPlaylist": "Přidat do Playlist",
|
||||||
|
"action.removeFromPlaylist": "Odstranit z Playlist",
|
||||||
|
"action.addToFavorites": "Přidat k oblíbeným",
|
||||||
|
"action.follow": "Sledovat",
|
||||||
|
"action.follow.success": "Sleduješ",
|
||||||
|
"action.follow.error": "Chyba sledování",
|
||||||
|
"action.unfollow": "Přestat sledovat",
|
||||||
|
"action.unfollow.success": "Nesledováno",
|
||||||
|
"action.unfollow.error": "Chyba při zrušení sledování",
|
||||||
|
"action.playNext": "Play Další",
|
||||||
|
"action.playLater": "Play Později",
|
||||||
|
"action.startRadio": "Start Rádio",
|
||||||
|
"action.goToArtist": "Přejít na Umělec",
|
||||||
|
"action.goToAlbum": "Přejděte do alba",
|
||||||
|
"action.moveToTop": "Přesunout nahoru",
|
||||||
|
"action.share": "Sdílet",
|
||||||
|
"action.rename": "Přejmenovat",
|
||||||
|
"action.love": "Milovat",
|
||||||
|
"action.unlove": "Nemilovat",
|
||||||
|
"action.dislike": "Dislike",
|
||||||
|
"action.undoDislike": "Undo dislike",
|
||||||
|
"action.showWebRemoteQR": "Web Remote",
|
||||||
|
"action.playTracksNext": "Play ${app.selectedMediaItems.length} tracks next",
|
||||||
|
"action.playTracksLater": "Play ${app.selectedMediaItems.length} tracks later",
|
||||||
|
"action.removeTracks": "Odstranit ${self.selectedItems.length} tracks from queue",
|
||||||
|
"action.import": "Importovať",
|
||||||
|
"action.export": "Exportovať",
|
||||||
|
"action.showAlbum": "Zobrazit kompletní album",
|
||||||
|
"action.tray.minimize": "Minimalizovat do lišty",
|
||||||
|
"action.tray.quit": "Přestat",
|
||||||
|
"action.tray.show": "Ukázat",
|
||||||
|
"action.update": "Aktualizace",
|
||||||
|
"action.copy": "kopírovat",
|
||||||
|
"action.newpreset": "Nová předvolba...", // Equalizer Preset
|
||||||
|
"action.deletepreset": "Smazat předvolbu",
|
||||||
|
|
||||||
|
// Settings - General
|
||||||
|
"settings.header.general": "Všeobecné",
|
||||||
|
"settings.header.general.description": "Upravte obecná nastavení pro Cider.",
|
||||||
|
"settings.option.general.language": "Jazyk",
|
||||||
|
|
||||||
|
// Language optgroups
|
||||||
|
"settings.option.general.language.main": "Jazyky",
|
||||||
|
"settings.option.general.language.fun": "Zábavné jazyky",
|
||||||
|
"settings.option.general.language.unsorted": "Neřazeno",
|
||||||
|
|
||||||
|
// Update Cider
|
||||||
|
"settings.option.general.updateCider": "Aktualizujte Cider", // Button. Refer to term.check for the check button
|
||||||
|
"settings.option.general.updateCider.branch": "Pobočka aktualizace cideru", // Dropdown
|
||||||
|
"settings.option.general.updateCider.branch.description": "Vyberte pobočku, do které chcete Cider aktualizovat",
|
||||||
|
"settings.option.general.updateCider.branch.main": "Stabilní",
|
||||||
|
"settings.option.general.updateCider.branch.develop": "Rozvoj",
|
||||||
|
|
||||||
|
// Settings - Audio
|
||||||
|
"settings.header.audio": "Zvuk",
|
||||||
|
"settings.header.audio.description": "Upravte nastavení zvuku pro Cider.",
|
||||||
|
"settings.option.audio.quality": "Kvalita zvuku", // Dropdown
|
||||||
|
"settings.header.audio.quality.hireslossless": "Hi-Res Lossless",
|
||||||
|
"settings.header.audio.quality.hireslossless.description": "až 24-bit/192 kHz",
|
||||||
|
"settings.header.audio.quality.lossless": "Lossless",
|
||||||
|
"settings.header.audio.quality.lossless.description": "až 24-bit/48 kHz",
|
||||||
|
"settings.header.audio.quality.high": "Vysoké",
|
||||||
|
"settings.header.audio.quality.high.description": "256 kbps",
|
||||||
|
"settings.header.audio.quality.standard": "Standard",
|
||||||
|
"settings.header.audio.quality.standard.description": "64 kbps",
|
||||||
|
"settings.option.audio.seamlessTransition": "Plynulý přechod zvuku", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality": "Povolit pokročilé funkce", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.description": "Povolení funkce AudioContext umožní rozšířené zvukové funkce, jako je normalizace zvuku, ekvalizéry a vizualizéry, ale na některých systémech to může způsobit zadrhávání ve zvukových stopách.",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™️", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Psychoakustická vylepšení, díky nimž vše zní bohatěji a živěji | Navrhl Maikiwi.",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "Síla CAP", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Změní sílu zpracování zvuku. (Agresivita může vést k nežádoucím výsledkům)",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "Standard",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "Agresivní",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Normalizace zvuku", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Normalizuje špičkovou hlasitost pro jednotlivé stopy a vytváří jednotnější zážitek z poslechu.",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Prostorovost zvuku", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Prostorově upravte zvuk a udělejte zvuk více 3-rozměrný (poznámka: Toto není Dolby Atmos)",
|
||||||
|
|
||||||
|
// Settings - Visual
|
||||||
|
"settings.header.visual": "Vizuální",
|
||||||
|
"settings.header.visual.description": "Upravte vizuální nastavení pro Cider.",
|
||||||
|
"settings.option.visual.windowBackgroundStyle": "Styl pozadí okna", // Toggle
|
||||||
|
"settings.header.visual.windowBackgroundStyle.none": "Žádný",
|
||||||
|
"settings.header.visual.windowBackgroundStyle.artwork": "Umělecké dílo",
|
||||||
|
"settings.header.visual.windowBackgroundStyle.image": "obraz",
|
||||||
|
"settings.option.visual.animatedArtwork": "Animované umělecké dílo", // Dropdown
|
||||||
|
"settings.header.visual.animatedArtwork.always": "Vždy",
|
||||||
|
"settings.header.visual.animatedArtwork.limited": "Omezeno na stránky a speciální položky",
|
||||||
|
"settings.header.visual.animatedArtwork.disable": "Zakázat všude",
|
||||||
|
"settings.option.visual.animatedArtworkQuality": "Kvalita animovaného uměleckého díla", // Dropdown
|
||||||
|
"settings.header.visual.animatedArtworkQuality.low": "Nízký",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.medium": "Střední",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.high": "Vysoký",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.veryHigh": "Velmi vysoký",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.extreme": "Extrémní",
|
||||||
|
"settings.option.visual.animatedWindowBackground": "Animované pozadí okna", // Toggle
|
||||||
|
"settings.option.visual.hardwareAcceleration": "Hardwarová akcelerace", // Dropdown
|
||||||
|
"settings.option.visual.hardwareAcceleration.description": "Vyžaduje opětovné spuštění",
|
||||||
|
"settings.header.visual.hardwareAcceleration.default": "Výchozí",
|
||||||
|
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
|
||||||
|
"settings.header.visual.theme": "Téma",
|
||||||
|
|
||||||
|
// Settings - Visual - Theme name
|
||||||
|
"settings.option.visual.theme.default": "Cider",
|
||||||
|
"settings.option.visual.theme.dark": "Temný",
|
||||||
|
// Refer to term.disabled for the disabled option
|
||||||
|
"settings.option.visual.showPersonalInfo": "Zobrazit osobní údaje", // Toggle
|
||||||
|
|
||||||
|
// Settings - Lyrics
|
||||||
|
"settings.header.lyrics": "Text",
|
||||||
|
"settings.header.lyrics.description": "Upravte nastavení textů pro Cider.",
|
||||||
|
"settings.option.lyrics.enableMusixmatch": "Povolit texty Musixmatch", // Toggle
|
||||||
|
"settings.option.lyrics.enableMusixmatchKaraoke": "Povolit režim karaoke (pouze Musixmatch)", // Toggle
|
||||||
|
"settings.option.lyrics.musixmatchPreferredLanguage": "Preferovaný jazyk překladu Musixmatch", // Dropdown
|
||||||
|
"settings.option.lyrics.enableYoutubeLyrics": "Povolit texty YouTube pro hudební videa", // Toggle
|
||||||
|
|
||||||
|
// Settings - Connectivity
|
||||||
|
"settings.header.connectivity": "Konektivita",
|
||||||
|
"settings.header.connectivity.description": "Upravte nastavení připojení pro Cider.",
|
||||||
|
"settings.option.connectivity.discordRPC": "Discord Rich Presence", // Dropdown
|
||||||
|
"settings.option.connectivity.playbackNotifications": "Oznámení o přehrávání", // Toggle
|
||||||
|
// Refer to term.disabled for the disabled option
|
||||||
|
"settings.header.connectivity.discordRPC.cider": "Zobrazit jako 'Cider'",
|
||||||
|
"settings.header.connectivity.discordRPC.appleMusic": "Zobrazit jako 'Apple Music'",
|
||||||
|
"settings.option.connectivity.discordRPC.clearOnPause": "Vymazat Discord Rich Presence on Pause", // Toggle
|
||||||
|
"settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling", // Option to Connect
|
||||||
|
"settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble Delay (%)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "Povolit Last.fm Now Playing",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "Odebrat z názvu písně vystupující interprety (Last.fm)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "Filtrovaná stopa ve smyčce (Last.fm)",
|
||||||
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
|
// Settings - Experimental
|
||||||
|
"settings.header.experimental": "Experimentální",
|
||||||
|
"settings.header.experimental.description": "Upravte experimentální nastavení pro Cider.",
|
||||||
|
"settings.option.experimental.compactUI": "Kompaktní uživatelské rozhraní", // Toggle
|
||||||
|
"settings.option.experimental.close_button_hide": "Tlačítko Zavřít by mělo aplikaci skrýt",
|
||||||
|
"settings.option.experimental.copy_log": "Zkopírujte protokoly do clipboard",
|
||||||
|
"settings.option.experimental.inline_playlists": "Vložené seznamy skladeb a alba",
|
||||||
|
|
||||||
|
// Refer to term.disabled & term.enabled
|
||||||
|
// Spatialization Menu
|
||||||
|
"spatial.notTurnedOn": "Prostorová funkce zvuku je zakázána. Chcete-li jej používat, nejprve jej povolte.",
|
||||||
|
"spatial.spatialProperties": "Prostorové vlastnosti",
|
||||||
|
"spatial.width": "Šířka",
|
||||||
|
"spatial.height": "Výška",
|
||||||
|
"spatial.depth": "Hloubka",
|
||||||
|
"spatial.gain": "Získat",
|
||||||
|
"spatial.roomMaterials": "Materiály místnosti",
|
||||||
|
"spatial.roomDimensions": "Rozměry místnosti",
|
||||||
|
"spatial.roomPositions": "Pozice místností",
|
||||||
|
"spatial.setDimensions": "Nastavit rozměry",
|
||||||
|
"spatial.setPositions": "Nastavení pozici",
|
||||||
|
"spatial.up": "Nahoru",
|
||||||
|
"spatial.front": "Přední",
|
||||||
|
"spatial.left": "Vlevo",
|
||||||
|
"spatial.right": "Pravo",
|
||||||
|
"spatial.back": "Zadní",
|
||||||
|
"spatial.down": "Dolů",
|
||||||
|
"spatial.listener": "Posluchač",
|
||||||
|
"spatial.audioSource": "Zdroj zvuku",
|
||||||
|
|
||||||
|
// Settings - Unfinished
|
||||||
|
"settings.header.unfinished": "Nedokončený",
|
||||||
|
|
||||||
|
// Web Remote
|
||||||
|
"remote.web.title": "Cider Remote",
|
||||||
|
"remote.web.description": "Naskenujte QR kód a spárujte svůj telefon s touto instancí Cider",
|
||||||
|
|
||||||
|
// About
|
||||||
|
"about.thanks": "Velké poděkování patří týmu Cider Collective Team a všem našim přispěvatelům."
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{ // en_PISS Note: This language uses the ellipsis symbol (…) instead of 3 dots.
|
||||||
|
|
||||||
// i18n Info
|
// i18n Info
|
||||||
"i18n.languageName": "piss", // name of language in native language
|
"i18n.languageName": "piss", // name of language in native language
|
||||||
|
@ -70,8 +70,9 @@
|
||||||
"term.sortBy.artist": "pissers",
|
"term.sortBy.artist": "pissers",
|
||||||
"term.sortBy.name": "piss name",
|
"term.sortBy.name": "piss name",
|
||||||
"term.sortBy.genre": "way to piss",
|
"term.sortBy.genre": "way to piss",
|
||||||
"term.sortBy.releaseDate": "pissed date",
|
"term.sortBy.releaseDate": "repissed date",
|
||||||
"term.sortBy.duration": "piss duration",
|
"term.sortBy.duration": "piss duration",
|
||||||
|
"term.sortBy.dateAdded": "obtained date",
|
||||||
"term.sortOrder": "piss-PISS",
|
"term.sortOrder": "piss-PISS",
|
||||||
"term.sortOrder.ascending": "pissing upwards",
|
"term.sortOrder.ascending": "pissing upwards",
|
||||||
"term.sortOrder.descending": "pissing downwards",
|
"term.sortOrder.descending": "pissing downwards",
|
||||||
|
@ -95,10 +96,10 @@
|
||||||
"term.showMore": "more piss",
|
"term.showMore": "more piss",
|
||||||
"term.showLess": "less piss",
|
"term.showLess": "less piss",
|
||||||
"term.topSongs": "top piss",
|
"term.topSongs": "top piss",
|
||||||
"term.latestReleases": "latest piss collection",
|
"term.latestReleases": "latest piss",
|
||||||
"term.time.added": "pissed",
|
"term.time.added": "obtained",
|
||||||
"term.time.released": "pissed",
|
"term.time.released": "repissed",
|
||||||
"term.time.updated": "pissed",
|
"term.time.updated": "pissdated",
|
||||||
"term.time.hours": "hours",
|
"term.time.hours": "hours",
|
||||||
"term.time.hour": "hour",
|
"term.time.hour": "hour",
|
||||||
"term.time.minutes": "minutes",
|
"term.time.minutes": "minutes",
|
||||||
|
@ -132,11 +133,13 @@
|
||||||
"term.sharedPlaylists": "shared pisslists", // Search Results
|
"term.sharedPlaylists": "shared pisslists", // Search Results
|
||||||
"term.people": "pissers", // Search Results
|
"term.people": "pissers", // Search Results
|
||||||
"term.newpreset.name": "new advanced piss prepiss name", // Equalizer Preset
|
"term.newpreset.name": "new advanced piss prepiss name", // Equalizer Preset
|
||||||
"term.addedpreset": "pissed prepiss",
|
"term.addedpreset": "obtained prepiss",
|
||||||
"term.deletepreset.warn": "are you sure you want to unpiss this prepiss?",
|
"term.deletepreset.warn": "are you sure you want to obliterate this prepiss?",
|
||||||
"term.deletedpreset": "unpissed prepiss",
|
"term.deletedpreset": "obliterated prepiss",
|
||||||
"term.musicVideos": "piss music videos", // Search page friendlyTypes
|
"term.requestError": "the request got pissed on",
|
||||||
"term.stations": "pisses",
|
"term.song.link.generate": "pissing on piss.link…",
|
||||||
|
"term.musicVideos": "piss videos", // Search page friendlyTypes
|
||||||
|
"term.stations": "piss stations",
|
||||||
"term.curators": "pissators",
|
"term.curators": "pissators",
|
||||||
"term.appleCurators": "piss pissators",
|
"term.appleCurators": "piss pissators",
|
||||||
"term.radioShows": "shows that piss everywhere",
|
"term.radioShows": "shows that piss everywhere",
|
||||||
|
@ -216,8 +219,8 @@
|
||||||
"action.tray.show": "piss back",
|
"action.tray.show": "piss back",
|
||||||
"action.update": "piss!",
|
"action.update": "piss!",
|
||||||
"action.copy": "copiss",
|
"action.copy": "copiss",
|
||||||
"action.newpreset": "new prepiss...", // Equalizer Preset
|
"action.newpreset": "new prepiss…", // Equalizer Preset
|
||||||
"action.deletepreset": "unpiss prepiss",
|
"action.deletepreset": "obliterate prepiss",
|
||||||
|
|
||||||
// Settings - General
|
// Settings - General
|
||||||
"settings.header.general": "general",
|
"settings.header.general": "general",
|
||||||
|
@ -230,25 +233,35 @@
|
||||||
"settings.option.general.language.unsorted": "???? who put this here",
|
"settings.option.general.language.unsorted": "???? who put this here",
|
||||||
|
|
||||||
// Update Cider
|
// Update Cider
|
||||||
"settings.option.general.updateCider": "piss on cider", // Button
|
"settings.option.general.updateCider": "piss on cider", // Button. Refer to term.check for the check button
|
||||||
|
"settings.option.general.updateCider.branch": "where to piss on cider", // Dropdown
|
||||||
|
"settings.option.general.updateCider.branch.description": "there are two toilets, where do you want to piss?",
|
||||||
|
"settings.option.general.updateCider.branch.main": "smooth pissing experience",
|
||||||
|
"settings.option.general.updateCider.branch.develop": "cutting-edge piss development",
|
||||||
|
|
||||||
// Settings - Audio
|
// Settings - Audio
|
||||||
"settings.header.audio": "piss sounds",
|
"settings.header.audio": "piss sounds",
|
||||||
"settings.header.audio.description": "change how your piss sounds",
|
"settings.header.audio.description": "change how your piss sounds",
|
||||||
"settings.option.audio.quality": "piss quality", // Dropdown
|
"settings.option.audio.quality": "piss quality", // Dropdown
|
||||||
"settings.header.audio.quality.hireslossless": "ungodly piss",
|
"settings.header.audio.quality.hireslossless": "ungodly piss",
|
||||||
"settings.header.audio.quality.hireslossless.description": "(up to 24-pisses/192 piss hertz)",
|
"settings.header.audio.quality.hireslossless.description": "up to 24-piss/192 pissHz",
|
||||||
"settings.header.audio.quality.lossless": "colorful piss",
|
"settings.header.audio.quality.lossless": "colorful piss",
|
||||||
"settings.header.audio.quality.lossless.description": "(up to 24-pisses/48 piss hertz)",
|
"settings.header.audio.quality.lossless.description": "up to 24-piss/48 pissHz",
|
||||||
"settings.header.audio.quality.enhanced": "enhanced piss",
|
"settings.header.audio.quality.enhanced": "business class piss",
|
||||||
"settings.header.audio.quality.high": "nice piss",
|
"settings.header.audio.quality.high": "nice piss",
|
||||||
"settings.header.audio.quality.low": "piss with blood",
|
"settings.header.audio.quality.high.description": "256 kpiss",
|
||||||
"settings.header.audio.quality.auto": "automatic piss",
|
"settings.header.audio.quality.standard": "piss with blood",
|
||||||
|
"settings.header.audio.quality.standard.description": "64 kpiss",
|
||||||
"settings.option.audio.seamlessTransition": "seamless piss-to-piss transition", // Toggle
|
"settings.option.audio.seamlessTransition": "seamless piss-to-piss transition", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality": "cool piss tricks", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality": "cool piss tricks", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.description": "enabling the AudioContext thingy allows you to do cool stuffs, however on some systems your song may stutter",
|
"settings.option.audio.enableAdvancedFunctionality.description": "enabling the AudioContext thingy allows you to do cool stuffs, however on some systems your song may stutter",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "clear piss™️", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Audio Pissifier™️", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "makes your bladder go overboard and makes your piss crisp and clear.",
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "makes your bladder go overboard and makes your piss crisp and clear",
|
||||||
|
"settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "pissifier dont go well with 3d piss. turn it off and try again.",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "pissifier strength", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "tune your bladder (blood may appear with turbo strength)",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "normal piss",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "turbo piss",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "piss normaliztion", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "piss normaliztion", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "protect your eardrums from overly loud/slient pisses",
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "protect your eardrums from overly loud/slient pisses",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "3D piss", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "3D piss", // Toggle
|
||||||
|
@ -279,7 +292,7 @@
|
||||||
"settings.header.visual.theme": "colored piss",
|
"settings.header.visual.theme": "colored piss",
|
||||||
|
|
||||||
// Settings - Visual - Theme name
|
// Settings - Visual - Theme name
|
||||||
"settings.option.visual.theme.default": "regular piss",
|
"settings.option.visual.theme.default": "same old piss",
|
||||||
"settings.option.visual.theme.dark": "black piss",
|
"settings.option.visual.theme.dark": "black piss",
|
||||||
|
|
||||||
// Refer to term.disabled for the disabled option
|
// Refer to term.disabled for the disabled option
|
||||||
|
@ -305,7 +318,7 @@
|
||||||
"settings.option.connectivity.lastfmScrobble": "Piss.fm scrobbling", // Option to Connect
|
"settings.option.connectivity.lastfmScrobble": "Piss.fm scrobbling", // Option to Connect
|
||||||
"settings.option.connectivity.lastfmScrobble.delay": "Piss.fm scrobble delay (%)",
|
"settings.option.connectivity.lastfmScrobble.delay": "Piss.fm scrobble delay (%)",
|
||||||
"settings.option.connectivity.lastfmScrobble.nowPlaying": "push now playing data to Piss.fm",
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "push now playing data to Piss.fm",
|
||||||
"settings.option.connectivity.lastfmScrobble.removeFeatured": "remove featured pissers from piss names (Piss.fm)",
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "dump featured pissers from piss names (Piss.fm)",
|
||||||
"settings.option.connectivity.lastfmScrobble.filterLoop": "filter same piss (Piss.fm)",
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "filter same piss (Piss.fm)",
|
||||||
// Refer to term.connect for the connect button
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
|
@ -344,7 +357,7 @@
|
||||||
|
|
||||||
// Web Remote
|
// Web Remote
|
||||||
"remote.web.title": "piss remote",
|
"remote.web.title": "piss remote",
|
||||||
"remote.web.description": "piss on your phone camera to connect to Cider.",
|
"remote.web.description": "piss on your phone camera to pair with Cider.",
|
||||||
|
|
||||||
// About
|
// About
|
||||||
"about.thanks": "thanks to the Cider Collective team and all the pisseneers putting this together"
|
"about.thanks": "thanks to the Cider Collective team and all the pisseneers putting this together"
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
"term.sortBy.genre": "Genre",
|
"term.sortBy.genre": "Genre",
|
||||||
"term.sortBy.releaseDate": "Release Date",
|
"term.sortBy.releaseDate": "Release Date",
|
||||||
"term.sortBy.duration": "Duration",
|
"term.sortBy.duration": "Duration",
|
||||||
|
"term.sortBy.dateAdded": "Date Added",
|
||||||
"term.sortOrder": "A-Z",
|
"term.sortOrder": "A-Z",
|
||||||
"term.sortOrder.ascending": "Ascending",
|
"term.sortOrder.ascending": "Ascending",
|
||||||
"term.sortOrder.descending": "Descending",
|
"term.sortOrder.descending": "Descending",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
|
|
||||||
// i18n Info
|
// i18n Info
|
||||||
"i18n.languageName": "English (US)", // name of language in native language
|
"i18n.languageName": "हिन्दी", // name of language in native language
|
||||||
"i18n.languageNameEnglish": "English (US)", // name of language in English
|
"i18n.languageNameEnglish": "Hindi", // name of language in English
|
||||||
"i18n.category": "main", // main = real language, fun = fun community languages
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
"i18n.authors": "@maikirakiwi @vringster", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
"i18n.authors": "@maikirakiwi @vringster", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
"term.time.second": "másodperc",
|
"term.time.second": "másodperc",
|
||||||
"term.fullscreenView": "Teljes képernyős mód",
|
"term.fullscreenView": "Teljes képernyős mód",
|
||||||
"term.defaultView": "Alapértelmezett nézet",
|
"term.defaultView": "Alapértelmezett nézet",
|
||||||
"term.spacializedAudioSetting": "Térbeli hang",
|
"term.audioSettings": "Hangbeállítások",
|
||||||
"term.clearAll": "Összes törlése",
|
"term.clearAll": "Összes törlése",
|
||||||
"term.recentStations": "Nemrég játszott",
|
"term.recentStations": "Nemrég játszott",
|
||||||
"term.language": "Nyelv",
|
"term.language": "Nyelv",
|
||||||
|
@ -131,9 +131,9 @@
|
||||||
"term.sharedPlaylists": "Megosztott lejátszási listák", // Search Results
|
"term.sharedPlaylists": "Megosztott lejátszási listák", // Search Results
|
||||||
"term.people": "Profilok", // Search Results
|
"term.people": "Profilok", // Search Results
|
||||||
"term.newpreset.name": "New EQ Preset Name", // Equalizer Preset
|
"term.newpreset.name": "New EQ Preset Name", // Equalizer Preset
|
||||||
"term.addedpreset": "Preset hozzáadva",
|
"term.addedpreset": "Előbeállítás hozzáadva",
|
||||||
"term.deletepreset.warn": "Are you sure you want to delete this preset?",
|
"term.deletepreset.warn": "Biztos törölni szeretnéd ezt az előbeállítást?",
|
||||||
"term.deletedpreset": "Preset törölve",
|
"term.deletedpreset": "Előbeállítás törölve",
|
||||||
"term.musicVideos": "Videóklipek", // Search page friendlyTypes
|
"term.musicVideos": "Videóklipek", // Search page friendlyTypes
|
||||||
"term.stations": "Állomások",
|
"term.stations": "Állomások",
|
||||||
"term.curators": "Curators",
|
"term.curators": "Curators",
|
||||||
|
@ -229,7 +229,11 @@
|
||||||
"settings.option.general.language.unsorted": "Azonosítatlan",
|
"settings.option.general.language.unsorted": "Azonosítatlan",
|
||||||
|
|
||||||
// Update Cider
|
// Update Cider
|
||||||
"settings.option.general.updateCider": "A Cider frissítése", // Button
|
"settings.option.general.updateCider": "Cider frissítése", // Button. Refer to term.check for the check button
|
||||||
|
"settings.option.general.updateCider.branch": "Verzió kiválasztása", // Dropdown
|
||||||
|
"settings.option.general.updateCider.branch.description": "Válaszd ki a Cider melyik verziójára szeretnél frissíteni",
|
||||||
|
"settings.option.general.updateCider.branch.main": "Normál",
|
||||||
|
"settings.option.general.updateCider.branch.develop": "Fejlesztői",
|
||||||
|
|
||||||
// Settings - Audio
|
// Settings - Audio
|
||||||
"settings.header.audio": "Hang",
|
"settings.header.audio": "Hang",
|
||||||
|
@ -315,7 +319,7 @@
|
||||||
// Settings - Experimental
|
// Settings - Experimental
|
||||||
"settings.header.experimental": "Kísérleti",
|
"settings.header.experimental": "Kísérleti",
|
||||||
"settings.header.experimental.description": "A Cider kísérleti beállításainak módosítása.",
|
"settings.header.experimental.description": "A Cider kísérleti beállításainak módosítása.",
|
||||||
"settings.option.experimental.compactUI": "Kompakt UI", // Toggle
|
"settings.option.experimental.compactUI": "Kompakt felület", // Toggle
|
||||||
"settings.option.experimental.close_button_hide": "A bezárás gomb rejtse el az alkalmazást",
|
"settings.option.experimental.close_button_hide": "A bezárás gomb rejtse el az alkalmazást",
|
||||||
"settings.option.experimental.copy_log": "Napló másolása a vágólapra",
|
"settings.option.experimental.copy_log": "Napló másolása a vágólapra",
|
||||||
"settings.option.experimental.inline_playlists": "Inline Playlists and Albums",
|
"settings.option.experimental.inline_playlists": "Inline Playlists and Albums",
|
||||||
|
|
|
@ -218,9 +218,9 @@
|
||||||
"settings.option.audio.seamlessTransition": "曲間なしで再生", // Toggle
|
"settings.option.audio.seamlessTransition": "曲間なしで再生", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality": "先進的な機能", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality": "先進的な機能", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.description": "AudioContext 機能を有効にすると、オーディオノーマライズ、空間オーディオ、イコライザーなどの機能を使用できますが、音が途切れるかもしれません。", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.description": "AudioContext 機能を有効にすると、オーディオノーマライズ、空間オーディオ、イコライザーなどの機能を使用できますが、音が途切れるかもしれません。", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider AEP™️", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™️", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "圧縮音源を高解像度に処理することによって、ロスレス相当の音質に向上させます。", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "圧縮音源を高解像度に処理することによって、ロスレス相当の音質に向上させます。", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "AEPの強さ", // Toggle
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "CAPの強さ", // Toggle
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Changes the strength of the processing done to the audio. (Aggressive may yield undesirable results)",
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Changes the strength of the processing done to the audio. (Aggressive may yield undesirable results)",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "標準",
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "標準",
|
||||||
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "高",
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "高",
|
||||||
|
|
364
src/i18n/vi_VN.jsonc
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
{ // Base File
|
||||||
|
|
||||||
|
// i18n Info
|
||||||
|
"i18n.languageName": "Tiếng Việt", // name of language in native language
|
||||||
|
"i18n.languageNameEnglish": "Vietnamese", // name of language in English
|
||||||
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
|
"i18n.authors": "@vapormusic", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
|
// App info
|
||||||
|
"app.name": "Cider",
|
||||||
|
|
||||||
|
"date.format": "${d} ${m}, ${y}",
|
||||||
|
|
||||||
|
// Dialogs
|
||||||
|
"dialog.cancel": "Cancel",
|
||||||
|
"dialog.ok": "OK",
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
"notification.updatingLibrarySongs": "Cập nhật bài hát trong thư viện...",
|
||||||
|
"notification.updatingLibraryAlbums": "Cập nhật album trong thư viện...",
|
||||||
|
"notification.updatingLibraryArtists": "Cập nhật ca sĩ trong thư viện...",
|
||||||
|
|
||||||
|
// Terms
|
||||||
|
"term.appleInc": "Apple Inc.",
|
||||||
|
"term.appleMusic": "Apple Music",
|
||||||
|
"term.applePodcasts": "Apple Podcasts",
|
||||||
|
"term.itunes": "iTunes",
|
||||||
|
"term.github": "GitHub",
|
||||||
|
"term.discord": "Discord",
|
||||||
|
"term.learnMore": "Tìm hiểu thêm",
|
||||||
|
"term.accountSettings": "Cài đặt tài khoản",
|
||||||
|
"term.logout": "Đăng xuất",
|
||||||
|
"term.login": "Đăng nhập",
|
||||||
|
"term.about": "Giới thiệu",
|
||||||
|
"term.privateSession": "Phiên dùng riêng tư",
|
||||||
|
"term.queue": "Hàng đợi",
|
||||||
|
"term.history": "Lịch sử",
|
||||||
|
"term.search": "Tìm kiếm",
|
||||||
|
"term.library": "Thư viện",
|
||||||
|
"term.listenNow": "Nghe ngay",
|
||||||
|
"term.browse": "Khám phá",
|
||||||
|
"term.radio": "Radio",
|
||||||
|
"term.recentlyAdded": "Vừa được thêm",
|
||||||
|
"term.songs": "Bài hát",
|
||||||
|
"term.albums": "Album",
|
||||||
|
"term.artists": "Nghệ sĩ",
|
||||||
|
"term.podcasts": "Podcast",
|
||||||
|
"term.playlists": "Playlist",
|
||||||
|
"term.playlist": "Playlist",
|
||||||
|
"term.newPlaylist": "Playlist mới",
|
||||||
|
"term.newPlaylistFolder": "Cụm playlist mới",
|
||||||
|
"term.createNewPlaylist": "Tạo playlist",
|
||||||
|
"term.createNewPlaylistFolder": "Tạo cụm playlist",
|
||||||
|
"term.deletePlaylist": "Bạn có muốn xoá playlist này?",
|
||||||
|
"term.play": "Phát",
|
||||||
|
"term.pause": "Dừng",
|
||||||
|
"term.previous": "Trước đó",
|
||||||
|
"term.next": "Tiếp theo",
|
||||||
|
"term.shuffle": "Xáo trộn",
|
||||||
|
"term.repeat": "Lặp",
|
||||||
|
"term.volume": "Âm lượng",
|
||||||
|
"term.mute": "Tắt tiếng",
|
||||||
|
"term.unmute": "Huỷ tắt tiếng",
|
||||||
|
"term.share": "Chia sẻ",
|
||||||
|
"term.share.success": "Đã lưu vào bộ nhớ tạm",
|
||||||
|
"term.settings": "Cài đặt",
|
||||||
|
"term.seeAll": "Xem tất cả",
|
||||||
|
"term.sortBy": "Xếp theo",
|
||||||
|
"term.sortBy.album": "Album",
|
||||||
|
"term.sortBy.artist": "Nghệ sĩ",
|
||||||
|
"term.sortBy.name": "Tên",
|
||||||
|
"term.sortBy.genre": "Dòng nhạc",
|
||||||
|
"term.sortBy.releaseDate": "Ngày phát hành",
|
||||||
|
"term.sortBy.duration": "Thời lượng",
|
||||||
|
"term.sortBy.dateAdded": "Ngày thêm vào",
|
||||||
|
"term.sortOrder": "A-Z",
|
||||||
|
"term.sortOrder.ascending": "Tăng dần",
|
||||||
|
"term.sortOrder.descending": "Giảm dần",
|
||||||
|
"term.viewAs": "Xem theo kiểu",
|
||||||
|
"term.viewAs.coverArt": "Ảnh bìa",
|
||||||
|
"term.viewAs.list": "Danh sách",
|
||||||
|
"term.size": "Cỡ",
|
||||||
|
"term.size.normal": "Vừa",
|
||||||
|
"term.size.compact": "Thu gọn",
|
||||||
|
"term.enable": "Bật",
|
||||||
|
"term.disable": "Tắt",
|
||||||
|
"term.enabled": "Đã bật",
|
||||||
|
"term.disabled": "Đã tắt",
|
||||||
|
"term.connect": "Kết nối",
|
||||||
|
"term.connecting": "Đang kết nối",
|
||||||
|
"term.disconnect": "Dừng kết nối",
|
||||||
|
"term.authed": "Đã đăng nhập",
|
||||||
|
"term.confirm": "Bạn có chăc không?",
|
||||||
|
"term.more": "Thêm",
|
||||||
|
"term.less": "Ít hơn",
|
||||||
|
"term.showMore": "Hiện thêm",
|
||||||
|
"term.showLess": "Hiện ít hơn",
|
||||||
|
"term.topSongs": "Các bài hát nổi bật",
|
||||||
|
"term.latestReleases": "Mới nhất",
|
||||||
|
"term.time.added": "Thêm vào ngày",
|
||||||
|
"term.time.released": "Phát hành vào ngày",
|
||||||
|
"term.time.updated": "Cập nhật vào ngày",
|
||||||
|
"term.time.hours": "giờ",
|
||||||
|
"term.time.hour": "giờ",
|
||||||
|
"term.time.minutes": "phút",
|
||||||
|
"term.time.minute": "phút",
|
||||||
|
"term.time.seconds": "giây",
|
||||||
|
"term.time.second": "giây",
|
||||||
|
"term.fullscreenView": "Xem toàn màn hình",
|
||||||
|
"term.defaultView": "Xem gốc",
|
||||||
|
"term.audioSettings": "Cài đặt âm thanh",
|
||||||
|
"term.clearAll": "Xoá tất cả",
|
||||||
|
"term.recentStations": "Các đài gần đây",
|
||||||
|
"term.language": "Ngôn ngữ",
|
||||||
|
"term.funLanguages": "Vui vẻ",
|
||||||
|
"term.noLyrics": "Đang tìm... / Không có lời bài hát.",
|
||||||
|
"term.copyright": "Bản quyền",
|
||||||
|
"term.rightsReserved": "Mọi quyền thuộc về các chủ sở hữu.",
|
||||||
|
"term.sponsor": "Tài trợ cho dự án này",
|
||||||
|
"term.ciderTeam": "Cider Team",
|
||||||
|
"term.developer": "Lập trình viên",
|
||||||
|
"term.socialTeam": "Social Team",
|
||||||
|
"term.socials": "PR",
|
||||||
|
"term.contributors": "Các đóng góp viên",
|
||||||
|
"term.equalizer": "EQ",
|
||||||
|
"term.reset": "Đặt về mặc định",
|
||||||
|
"term.tracks": "bài", // Assume x amount of tracks. e.g. 50 tracks
|
||||||
|
"term.videos": "Video",
|
||||||
|
"term.menu": "Menu",
|
||||||
|
"term.check": "Kiểm tra",
|
||||||
|
"term.aboutArtist": "Về {{artistName}}", // e.g. 'About Doja Cat'
|
||||||
|
"term.topResult": "Kết quả gần nhất", // Search Results
|
||||||
|
"term.sharedPlaylists": "Playlist được chia sẻ", // Search Results
|
||||||
|
"term.people": "Người dùng", // Search Results
|
||||||
|
"term.newpreset.name": "Tạo thiét lập EQ", // Equalizer Preset
|
||||||
|
"term.addedpreset": "Các thiét lập EQ đã được thêm", // Equalizer Preset
|
||||||
|
"term.deletepreset.warn": "Bạn có muốn xoá thiết lập này?",
|
||||||
|
"term.deletedpreset": "Thiết lập đã bị xoá",
|
||||||
|
"term.requestError": "Có vấn đề khi thực hiện yêu cầu.",
|
||||||
|
"term.song.link.generate": "Tìm URL danh mục trên song.link ...",
|
||||||
|
"term.musicVideos": "Video ca nhạc", // Search page friendlyTypes
|
||||||
|
"term.stations": "Các đài",
|
||||||
|
"term.curators": "Nhà tuyển chọn",
|
||||||
|
"term.appleCurators": "Tuyển chọn từ Apple",
|
||||||
|
"term.radioShows": "Các chương trình radio",
|
||||||
|
"term.recordLabels": "Nhà phát hành âm nhạc",
|
||||||
|
"term.videoExtras": "Video khác",
|
||||||
|
"term.top": "Top",
|
||||||
|
|
||||||
|
// Home
|
||||||
|
"home.title": "Chính",
|
||||||
|
"home.recentlyPlayed": "Mới phát",
|
||||||
|
"home.recentlyAdded": "Mới thêm vào",
|
||||||
|
"home.artistsFeed": "Theo dõi",
|
||||||
|
"home.artistsFeed.noArtist": "Theo dõi các nhạc sĩ mà bạn yêu thích và nhận thông báo khi có bài hát mới.",
|
||||||
|
"home.madeForYou": "Dành cho bạn",
|
||||||
|
"home.friendsListeningTo": "Bạn bè đang nghe",
|
||||||
|
"home.followedArtists": "Các nghệ sĩ đang theo dõi",
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
"error.appleMusicSubRequired": "Apple Music yêu cầu bạn đăng kí.",
|
||||||
|
"error.connectionError": "Có vấn đề kết nối tới Apple Music.",
|
||||||
|
"error.noResults": "Không có kết quả.",
|
||||||
|
"error.noResults.description": "Hãy thử tìm kiếm bẳng từ khoá khác.",
|
||||||
|
|
||||||
|
// Podcasts
|
||||||
|
"podcast.followOnCider": "Theo dõi trên Cider",
|
||||||
|
"podcast.followedOnCider": "Đang theo dõi trên Cider",
|
||||||
|
"podcast.subscribeOnItunes": "Theo dõi trên iTunes",
|
||||||
|
"podcast.subscribedOnItunes": "Đang theo dõi trên iTunes",
|
||||||
|
"podcast.itunesStore": "Cửa hàng iTunes",
|
||||||
|
"podcast.episodes": "Các tập",
|
||||||
|
"podcast.playEpisode": "Phát",
|
||||||
|
"podcast.website": "Trang chủ",
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
"action.addToLibrary": "Thêm vào thư viện",
|
||||||
|
"action.addToLibrary.success": "Đã thêm vào thư viện",
|
||||||
|
"action.addToLibrary.error": "Có lỗi khi thêm vào thư viện",
|
||||||
|
"action.removeFromLibrary": "Xoá khỏi thư viện",
|
||||||
|
"action.removeFromLibrary.success": "Đã xoá khỏi thư viện",
|
||||||
|
"action.addToQueue": "Thêm vào hàng đợi",
|
||||||
|
"action.addToQueue.success": "Đã thêm vào hàng đợi",
|
||||||
|
"action.addToQueue.error": "Có lỗi khi thêm vào hàng đợi",
|
||||||
|
"action.removeFromQueue": "Xoá khỏi hàng đợi",
|
||||||
|
"action.removeFromQueue.success": "Đã xoá khỏi hàng đợi",
|
||||||
|
"action.removeFromQueue.error": "Có lỗi khi xoá khỏi hàng đợi",
|
||||||
|
"action.createPlaylist": "Tạo playlist",
|
||||||
|
"action.addToPlaylist": "Thêm vào playlist",
|
||||||
|
"action.removeFromPlaylist": "Xoá khỏi playlist",
|
||||||
|
"action.addToFavorites": "Thêm vào Yêu thích",
|
||||||
|
"action.follow": "Theo dõi",
|
||||||
|
"action.follow.success": "Đã theo dõi",
|
||||||
|
"action.follow.error": "Có lỗi khi theo dõi",
|
||||||
|
"action.unfollow": "Ngừng theo dõi",
|
||||||
|
"action.unfollow.success": "Đã ngừng theo dõi",
|
||||||
|
"action.unfollow.error": "Có lỗi khi ngừng theo dõi",
|
||||||
|
"action.playNext": "Phát tiếp theo",
|
||||||
|
"action.playLater": "Phát cuối cùng",
|
||||||
|
"action.startRadio": "Tạo đài phát",
|
||||||
|
"action.goToArtist": "Đi đến nghệ sĩ",
|
||||||
|
"action.goToAlbum": "Đi đến album",
|
||||||
|
"action.moveToTop": "Đưa lên đầu",
|
||||||
|
"action.share": "Chia sẻ",
|
||||||
|
"action.rename": "Đổi tên",
|
||||||
|
"action.love": "Yêu thích",
|
||||||
|
"action.unlove": "Bỏ yêu thích",
|
||||||
|
"action.dislike": "Không thích",
|
||||||
|
"action.undoDislike": "Bỏ không thích",
|
||||||
|
"action.showWebRemoteQR": "Điều khiển từ xa",
|
||||||
|
"action.playTracksNext": "Phát ${app.selectedMediaItems.length} bài tiếp theo",
|
||||||
|
"action.playTracksLater": "Phát ${app.selectedMediaItems.length} bài cuối cùng",
|
||||||
|
"action.removeTracks": "Bỏ ${self.selectedItems.length} bài khỏi hàng đợi",
|
||||||
|
"action.import": "Nhập",
|
||||||
|
"action.export": "Xuất",
|
||||||
|
"action.showAlbum": "Hiện album đầy đủ",
|
||||||
|
"action.tray.minimize": "Thu nhỏ xuống khay hệ thống",
|
||||||
|
"action.tray.quit": "Thoát",
|
||||||
|
"action.tray.show": "Hiện",
|
||||||
|
"action.update": "Cập nhật",
|
||||||
|
"action.copy": "Sao chép",
|
||||||
|
"action.newpreset": "Thiếp lập mới...", // Equalizer Preset
|
||||||
|
"action.deletepreset": "Xoá thiêt lập",
|
||||||
|
|
||||||
|
// Settings - General
|
||||||
|
"settings.header.general": "Cài đặt chung",
|
||||||
|
"settings.header.general.description": "Thay đổi các cài đặt chung của Cider.",
|
||||||
|
"settings.option.general.language": "Ngôn ngữ",
|
||||||
|
|
||||||
|
// Language optgroups
|
||||||
|
"settings.option.general.language.main": "Ngôn ngữ chính",
|
||||||
|
"settings.option.general.language.fun": "Ngôn ngữ hư cấu",
|
||||||
|
"settings.option.general.language.unsorted": "Ngôn ngữ khác",
|
||||||
|
|
||||||
|
// Update Cider
|
||||||
|
"settings.option.general.updateCider": "Cập nhật Cider", // Button. Refer to term.check for the check button
|
||||||
|
"settings.option.general.updateCider.branch": "Nhánh cập nhật", // Dropdown
|
||||||
|
"settings.option.general.updateCider.branch.description": "Chọn nhánh cập nhật của Cider:",
|
||||||
|
"settings.option.general.updateCider.branch.main": "Ổn định",
|
||||||
|
"settings.option.general.updateCider.branch.develop": "Thử nghiệm",
|
||||||
|
|
||||||
|
// Settings - Audio
|
||||||
|
"settings.header.audio": "Âm thanh",
|
||||||
|
"settings.header.audio.description": "Thay đổi các cài đặt âm thanh của Cider.",
|
||||||
|
"settings.option.audio.quality": "Chất lượng âm thanh", // Dropdown
|
||||||
|
"settings.header.audio.quality.hireslossless": "Hi-Res Lossless",
|
||||||
|
"settings.header.audio.quality.hireslossless.description": "lên tới 24-bit/192 kHz",
|
||||||
|
"settings.header.audio.quality.lossless": "Lossless",
|
||||||
|
"settings.header.audio.quality.lossless.description": "lên tới 24-bit/48 kHz",
|
||||||
|
"settings.header.audio.quality.high": "Cao",
|
||||||
|
"settings.header.audio.quality.high.description": "256 kbps",
|
||||||
|
"settings.header.audio.quality.standard": "Tiêu chuẩn",
|
||||||
|
"settings.header.audio.quality.standard.description": "64 kbps",
|
||||||
|
"settings.option.audio.seamlessTransition": "Gapless playback", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality": "Kích hoạt chính năng nâng cao", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.description": "Bật các chức năng nâng cao sẽ kích hoạt các chức năng như EQ, Chuẩn hoá âm lượng hay Visualizer, tuy nhiên có thể sẽ ảnh hưởng tới chất lượng âm thanh",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™️", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Các tinh chỉnh về âm thanh giúp cho nhạc của bạn ấm và rõ hơn | Tạo bởi Maikiwi.",
|
||||||
|
"settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "CAP không tương thích với Âm thanh đa chiều. Hãy tắt Âm thanh đa chiều để kích hoạt.",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "CAP Strength", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Chỉnh mức độ ảnh hưởng của CAP đến âm thanh. (Chế độ Mạnh có thể ảnh hưởng đến âm thanh của bạn)",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "Tiêu chuẩn",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "Mạnh",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Chuẩn hoá âm lượng", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Đặt cùng mức âm lượng cho mọi bài hát",
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Tạo Âm thanh đa chiều ", // Toggle
|
||||||
|
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Làm cho âm thanh trở nên nhiều chiều hơn (Ghi chú: Đây không phải là Dolby Atmos)",
|
||||||
|
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "Âm thanh đa chiều không tương thích với CAP. Hãy tắt CAP để kích hoạt.",
|
||||||
|
|
||||||
|
// Settings - Visual
|
||||||
|
"settings.header.visual": "Hiển thị",
|
||||||
|
"settings.header.visual.description": "Thay đổi các cài đặt hiển thị của Cider.",
|
||||||
|
"settings.option.visual.windowBackgroundStyle": "Chế độ ảnh nền", // Toggle
|
||||||
|
"settings.header.visual.windowBackgroundStyle.none": "Không",
|
||||||
|
"settings.header.visual.windowBackgroundStyle.artwork": "Ảnh bìa",
|
||||||
|
"settings.header.visual.windowBackgroundStyle.image": "Ảnh",
|
||||||
|
"settings.option.visual.animatedArtwork": "Ảnh bìa động", // Dropdown
|
||||||
|
"settings.header.visual.animatedArtwork.always": "Luôn bật",
|
||||||
|
"settings.header.visual.animatedArtwork.limited": "Chỉ hiện ở mốt số trang cá nhân",
|
||||||
|
"settings.header.visual.animatedArtwork.disable": "Tắt",
|
||||||
|
"settings.option.visual.animatedArtworkQuality": "Chất lượng ảnh bìa động", // Dropdown
|
||||||
|
"settings.header.visual.animatedArtworkQuality.low": "Thấp",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.medium": "Trung bình",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.high": "Cao",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.veryHigh": "Rất cao",
|
||||||
|
"settings.header.visual.animatedArtworkQuality.extreme": "Rất rất cao",
|
||||||
|
"settings.option.visual.animatedWindowBackground": "Hình nền chuyển động", // Toggle
|
||||||
|
"settings.option.visual.hardwareAcceleration": "Chế độ Hiển thị", // Dropdown
|
||||||
|
"settings.option.visual.hardwareAcceleration.description": "Yêu cầu restart lại Cider để kích hoạt",
|
||||||
|
"settings.header.visual.hardwareAcceleration.default": "Gốc",
|
||||||
|
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
|
||||||
|
"settings.header.visual.theme": "Chủ đề",
|
||||||
|
|
||||||
|
// Settings - Visual - Theme name
|
||||||
|
"settings.option.visual.theme.default": "Cider",
|
||||||
|
"settings.option.visual.theme.dark": "Tối hơn",
|
||||||
|
|
||||||
|
// Refer to term.disabled for the disabled option
|
||||||
|
"settings.option.visual.showPersonalInfo": "Hiện thông tin cá nhân", // Toggle
|
||||||
|
|
||||||
|
// Settings - Lyrics
|
||||||
|
"settings.header.lyrics": "Lời bài hát",
|
||||||
|
"settings.header.lyrics.description": "Thay đổi các cài đặt lời bài hát của Cider.",
|
||||||
|
"settings.option.lyrics.enableMusixmatch": "Dùng lời từ Musixmatch", // Toggle
|
||||||
|
"settings.option.lyrics.enableMusixmatchKaraoke": "Bật chế độ karaoke (chỉ trên lời từ Musixmatch)", // Toggle
|
||||||
|
"settings.option.lyrics.musixmatchPreferredLanguage": "Ngôn ngữ dịch của Musixmatch", // Dropdown
|
||||||
|
"settings.option.lyrics.enableYoutubeLyrics": "Dùng lời từ Youtube cho các Video ca nhạc", // Toggle
|
||||||
|
|
||||||
|
// Settings - Connectivity
|
||||||
|
"settings.header.connectivity": "Kết nối",
|
||||||
|
"settings.header.connectivity.description": "Thay đổi các cài đặt lời kết nối của Cider.",
|
||||||
|
"settings.option.connectivity.discordRPC": "Discord Rich Presence", // Dropdown
|
||||||
|
"settings.option.connectivity.playbackNotifications": "Thông báo chuyển bài", // Toggle
|
||||||
|
// Refer to term.disabled for the disabled option
|
||||||
|
"settings.header.connectivity.discordRPC.cider": "Hiện là 'Cider'",
|
||||||
|
"settings.header.connectivity.discordRPC.appleMusic": "Hiện là 'Apple Music'",
|
||||||
|
"settings.option.connectivity.discordRPC.clearOnPause": "Xoá Discord Rich Presence khi dừng nhạc", // Toggle
|
||||||
|
"settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling", // Option to Connect
|
||||||
|
"settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble Delay (%)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "Bật Last.fm Now Playing",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "Xoá các nghệ sĩ phối hợp ở tên bài hát (Last.fm)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "Lọc các bài trùng (Last.fm)",
|
||||||
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
|
// Settings - Experimental
|
||||||
|
"settings.header.experimental": "Thử nghiệm",
|
||||||
|
"settings.header.experimental.description": "Thay đổi các cài đặt lời thử nghiệm của Cider.",
|
||||||
|
"settings.option.experimental.compactUI": "UI thu gọn", // Toggle
|
||||||
|
"settings.option.experimental.close_button_hide": "Nút thoát cửa số sẽ ẩn Cider xuống khay hệ thống",
|
||||||
|
"settings.option.experimental.copy_log": "Sao chép logs ra bộ nhớ tạm",
|
||||||
|
"settings.option.experimental.inline_playlists": "Playlists and Albums hiện nổi lên trên",
|
||||||
|
|
||||||
|
// Refer to term.disabled & term.enabled
|
||||||
|
// Spatialization Menu
|
||||||
|
"spatial.notTurnedOn": "Âm thanh đa chiều chưa được kích hoạt. Hãy kích hoạt nó trước",
|
||||||
|
"spatial.spatialProperties": "Tinh chỉnh cho Âm thanh đa chiều",
|
||||||
|
"spatial.width": "Chiều rộng",
|
||||||
|
"spatial.height": "Chiều cao",
|
||||||
|
"spatial.depth": "Chiều sâu",
|
||||||
|
"spatial.gain": "Gain",
|
||||||
|
"spatial.roomMaterials": "Chất liệu phòng",
|
||||||
|
"spatial.roomDimensions": "Kích thước phòng",
|
||||||
|
"spatial.roomPositions": "Vị trí phòng",
|
||||||
|
"spatial.setDimensions": "Chỉnh kích thước",
|
||||||
|
"spatial.setPositions": "Chỉnh vị trí",
|
||||||
|
"spatial.up": "Trên",
|
||||||
|
"spatial.front": "Trước",
|
||||||
|
"spatial.left": "Trái",
|
||||||
|
"spatial.right": "Phải",
|
||||||
|
"spatial.back": "Sau",
|
||||||
|
"spatial.down": "Dưới",
|
||||||
|
"spatial.listener": "Người nghe",
|
||||||
|
"spatial.audioSource": "Nguồn âm thanh",
|
||||||
|
|
||||||
|
// Settings - Unfinished
|
||||||
|
"settings.header.unfinished": "Chưa hoàn thiện",
|
||||||
|
|
||||||
|
// Web Remote
|
||||||
|
"remote.web.title": "Điều khiển từ xa của Cider",
|
||||||
|
"remote.web.description": "Quét mã QR để kết nối thiết bị của bạn với Cider",
|
||||||
|
|
||||||
|
// About
|
||||||
|
"about.thanks": "Trân trọng cảm ơn Cider Collective Team và tất cả các đóng góp viên của chúng tôi."
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"i18n.languageName": "简体中文(中国)", // name of language in native language
|
"i18n.languageName": "简体中文(中国)", // name of language in native language
|
||||||
"i18n.languageNameEnglish": "Simp. Chinese (China)", // name of language in English
|
"i18n.languageNameEnglish": "Simp. Chinese (China)", // name of language in English
|
||||||
"i18n.category": "main", // main = real language, fun = fun community languages
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
"i18n.authors": "@maikirakiwi", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
"i18n.authors": "@maikirakiwi @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
// App info
|
// App info
|
||||||
"app.name": "Cider",
|
"app.name": "Cider",
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
"notification.updatingLibraryArtists": "正在更新资料库的艺人信息...",
|
"notification.updatingLibraryArtists": "正在更新资料库的艺人信息...",
|
||||||
|
|
||||||
// Terms
|
// Terms
|
||||||
|
"term.appleInc": "Apple Inc.",
|
||||||
"term.appleMusic": "Apple Music", // Follows brand term
|
"term.appleMusic": "Apple Music", // Follows brand term
|
||||||
"term.applePodcasts": "Apple Podcasts", // Follows brand term
|
"term.applePodcasts": "Apple Podcasts", // Follows brand term
|
||||||
"term.itunes": "iTunes", // Follows brand term
|
"term.itunes": "iTunes", // Follows brand term
|
||||||
|
@ -45,6 +46,11 @@
|
||||||
"term.podcasts": "播客",
|
"term.podcasts": "播客",
|
||||||
"term.playlists": "播放列表",
|
"term.playlists": "播放列表",
|
||||||
"term.playlist": "播放列表",
|
"term.playlist": "播放列表",
|
||||||
|
"term.newPlaylist": "新播放列表",
|
||||||
|
"term.newPlaylistFolder": "新播放列表文件夹",
|
||||||
|
"term.createNewPlaylist": "新建播放列表",
|
||||||
|
"term.createNewPlaylistFolder": "新建播放列表文件夹",
|
||||||
|
"term.deletePlaylist": "您确定要删除该播放列表吗?",
|
||||||
"term.play": "播放",
|
"term.play": "播放",
|
||||||
"term.pause": "暂停",
|
"term.pause": "暂停",
|
||||||
"term.previous": "上一首",
|
"term.previous": "上一首",
|
||||||
|
@ -55,6 +61,7 @@
|
||||||
"term.mute": "静音",
|
"term.mute": "静音",
|
||||||
"term.unmute": "解除静音",
|
"term.unmute": "解除静音",
|
||||||
"term.share": "分享",
|
"term.share": "分享",
|
||||||
|
"term.share.success": "已复制到剪贴板",
|
||||||
"term.settings": "设置",
|
"term.settings": "设置",
|
||||||
"term.seeAll": "查看全部",
|
"term.seeAll": "查看全部",
|
||||||
"term.sortBy": "排序",
|
"term.sortBy": "排序",
|
||||||
|
@ -104,7 +111,7 @@
|
||||||
"term.clearAll": "清空",
|
"term.clearAll": "清空",
|
||||||
"term.recentStations": "最近播放的频道",
|
"term.recentStations": "最近播放的频道",
|
||||||
"term.language": "语言",
|
"term.language": "语言",
|
||||||
"term.noLyrics": "加载中。。/ 搜索无结果 / 纯音乐",
|
"term.noLyrics": "加载中... / 搜索无结果 / 纯音乐",
|
||||||
"term.copyright": "版权所有",
|
"term.copyright": "版权所有",
|
||||||
"term.rightsReserved": "保留所有权利。",
|
"term.rightsReserved": "保留所有权利。",
|
||||||
"term.sponsor": "赞助",
|
"term.sponsor": "赞助",
|
||||||
|
@ -119,13 +126,14 @@
|
||||||
"term.menu": "菜单",
|
"term.menu": "菜单",
|
||||||
"term.check": "检查",
|
"term.check": "检查",
|
||||||
"term.aboutArtist": "关于{{artistName}}", // e.g. 'About Doja Cat'
|
"term.aboutArtist": "关于{{artistName}}", // e.g. 'About Doja Cat'
|
||||||
|
"term.updateCider": "更新 Cider",
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
"home.title": "主页",
|
"home.title": "主页",
|
||||||
"home.recentlyPlayed": "最近播放",
|
"home.recentlyPlayed": "最近播放",
|
||||||
"home.recentlyAdded": "最近添加",
|
"home.recentlyAdded": "最近添加",
|
||||||
"home.artistsFeed": "艺人推荐",
|
"home.artistsFeed": "艺人推荐",
|
||||||
"home.artistsFeed.noArtist": "追踪您喜爱的艺人后便可查看他们的最新发行。",
|
"home.artistsFeed.noArtist": "关注您喜爱的艺人后便可查看他们的最新发行歌曲。",
|
||||||
"home.madeForYou": "专属推荐",
|
"home.madeForYou": "专属推荐",
|
||||||
"home.friendsListeningTo": "朋友正在听",
|
"home.friendsListeningTo": "朋友正在听",
|
||||||
"home.followedArtists": "关注的艺人",
|
"home.followedArtists": "关注的艺人",
|
||||||
|
@ -137,8 +145,8 @@
|
||||||
"error.noResults.description": "尝试更改搜索条件。",
|
"error.noResults.description": "尝试更改搜索条件。",
|
||||||
|
|
||||||
// Podcasts
|
// Podcasts
|
||||||
"podcast.followOnCider": "在 Cider 中追踪",
|
"podcast.followOnCider": "在 Cider 中关注",
|
||||||
"podcast.followedOnCider": "已追踪",
|
"podcast.followedOnCider": "已关注",
|
||||||
"podcast.subscribeOnItunes": "在 iTunes 上订阅",
|
"podcast.subscribeOnItunes": "在 iTunes 上订阅",
|
||||||
"podcast.subscribedOnItunes": "已订阅",
|
"podcast.subscribedOnItunes": "已订阅",
|
||||||
"podcast.itunesStore": "iTunes Store", // Follow brand term
|
"podcast.itunesStore": "iTunes Store", // Follow brand term
|
||||||
|
@ -152,12 +160,12 @@
|
||||||
"action.addToLibrary.error": "加入资料库的过程发生了错误",
|
"action.addToLibrary.error": "加入资料库的过程发生了错误",
|
||||||
"action.removeFromLibrary": "从资料库中移除",
|
"action.removeFromLibrary": "从资料库中移除",
|
||||||
"action.removeFromLibrary.success": "已从资料库中移除",
|
"action.removeFromLibrary.success": "已从资料库中移除",
|
||||||
"action.addToQueue": "加入队列",
|
"action.addToQueue": "加入待播清单",
|
||||||
"action.addToQueue.success": "成功加入队列",
|
"action.addToQueue.success": "成功加入加入待播清单",
|
||||||
"action.addToQueue.error": "加入队列的过程发生了错误",
|
"action.addToQueue.error": "加入加入待播清单的过程发生了错误",
|
||||||
"action.removeFromQueue": "从队列中移除",
|
"action.removeFromQueue": "从加入待播清单中移除",
|
||||||
"action.removeFromQueue.success": "已从队列中移除",
|
"action.removeFromQueue.success": "已从加入待播清单中移除",
|
||||||
"action.removeFromQueue.error": "从队列中移除的过程发生了错误",
|
"action.removeFromQueue.error": "从加入待播清单中移除的过程发生了错误",
|
||||||
"action.addToPlaylist": "加入播放列表",
|
"action.addToPlaylist": "加入播放列表",
|
||||||
"action.removeFromPlaylist": "从播放列表中移除",
|
"action.removeFromPlaylist": "从播放列表中移除",
|
||||||
"action.addToFavorites": "加至收藏",
|
"action.addToFavorites": "加至收藏",
|
||||||
|
@ -167,7 +175,7 @@
|
||||||
"action.unfollow": "取消关注",
|
"action.unfollow": "取消关注",
|
||||||
"action.unfollow.success": "已取消关注",
|
"action.unfollow.success": "已取消关注",
|
||||||
"action.unfollow.error": "尝试取消关注的过程发生了错误",
|
"action.unfollow.error": "尝试取消关注的过程发生了错误",
|
||||||
"action.playNext": "下一首播放",
|
"action.playNext": "插播",
|
||||||
"action.playLater": "最后播放",
|
"action.playLater": "最后播放",
|
||||||
"action.startRadio": "开始电台",
|
"action.startRadio": "开始电台",
|
||||||
"action.goToArtist": "前往艺人",
|
"action.goToArtist": "前往艺人",
|
||||||
|
@ -178,7 +186,7 @@
|
||||||
"action.love": "喜欢",
|
"action.love": "喜欢",
|
||||||
"action.unlove": "踩",
|
"action.unlove": "踩",
|
||||||
"action.dislike": "减少此类建议",
|
"action.dislike": "减少此类建议",
|
||||||
"action.undoDislike": "增加此类建议",
|
"action.undoDislike": "撤销减少此类建议",
|
||||||
"action.showWebRemoteQR": "显示远程控制的二维码",
|
"action.showWebRemoteQR": "显示远程控制的二维码",
|
||||||
"action.playTracksNext": "插播 ${app.selectedMediaItems.length} 首歌曲",
|
"action.playTracksNext": "插播 ${app.selectedMediaItems.length} 首歌曲",
|
||||||
"action.playTracksLater": "最后播放 ${app.selectedMediaItems.length} 首歌曲",
|
"action.playTracksLater": "最后播放 ${app.selectedMediaItems.length} 首歌曲",
|
||||||
|
@ -245,6 +253,8 @@
|
||||||
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
|
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
|
||||||
|
|
||||||
// Settings - Visual - Theme name
|
// Settings - Visual - Theme name
|
||||||
|
"settings.option.visual.theme.default": "默认",
|
||||||
|
"settings.option.visual.theme.dark": "午夜黑",
|
||||||
|
|
||||||
// Refer to term.disabled for the disabled option
|
// Refer to term.disabled for the disabled option
|
||||||
"settings.option.visual.showPersonalInfo": "显示个人资料", // Toggle
|
"settings.option.visual.showPersonalInfo": "显示个人资料", // Toggle
|
||||||
|
@ -261,14 +271,16 @@
|
||||||
"settings.header.connectivity": "外部连接",
|
"settings.header.connectivity": "外部连接",
|
||||||
"settings.header.connectivity.description": "调整Cider与外部应用的交互设置",
|
"settings.header.connectivity.description": "调整Cider与外部应用的交互设置",
|
||||||
"settings.option.connectivity.discordRPC": "Discord 动态", // Dropdown
|
"settings.option.connectivity.discordRPC": "Discord 动态", // Dropdown
|
||||||
|
"settings.option.connectivity.playbackNotifications": "歌曲播放通知", // Toggle
|
||||||
// Refer to term.disabled for the disabled option
|
// Refer to term.disabled for the disabled option
|
||||||
"settings.header.connectivity.discordRPC.cider": "显示正在玩 'Cider'",
|
"settings.header.connectivity.discordRPC.cider": "显示正在使用 'Cider'",
|
||||||
"settings.header.connectivity.discordRPC.appleMusic": "显示正在玩 'Apple Music'",
|
"settings.header.connectivity.discordRPC.appleMusic": "显示正在使用 'Apple Music'",
|
||||||
"settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态", // Toggle
|
"settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态", // Toggle
|
||||||
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 记录", // Option to Connect
|
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 记录", // Option to Connect
|
||||||
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延迟 (%)",
|
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延迟 (%)",
|
||||||
"settings.option.connectivity.lastfmScrobble.nowPlaying": "启用 LastFM 正在播放",
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "启用 LastFM 正在播放",
|
||||||
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除艺人推荐 (LastFM)",
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (LastFM)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (LastFM)",
|
||||||
// Refer to term.connect for the connect button
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
// Settings - Experimental
|
// Settings - Experimental
|
||||||
|
@ -279,6 +291,7 @@
|
||||||
|
|
||||||
// Refer to term.disabled & term.enabled
|
// Refer to term.disabled & term.enabled
|
||||||
// Spatialization Menu
|
// Spatialization Menu
|
||||||
|
"spatial.notTurnedOn": "请在设定中开启空间音频。",
|
||||||
"spatial.spatialProperties": "空间属性",
|
"spatial.spatialProperties": "空间属性",
|
||||||
"spatial.width": "宽度",
|
"spatial.width": "宽度",
|
||||||
"spatial.height": "高度",
|
"spatial.height": "高度",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"i18n.languageName": "繁體中文(香港)", // name of language in native language
|
"i18n.languageName": "繁體中文(香港)", // name of language in native language
|
||||||
"i18n.languageNameEnglish": "Trad. Chinese (Hong Kong)", // name of language in English
|
"i18n.languageNameEnglish": "Trad. Chinese (Hong Kong)", // name of language in English
|
||||||
"i18n.category": "main", // main = real language, fun = fun community languages
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
"i18n.authors": "@kyw504100 @maikirakiwi", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
"i18n.authors": "@kyw504100 @maikirakiwi @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
// App info
|
// App info
|
||||||
"app.name": "Cider",
|
"app.name": "Cider",
|
||||||
|
@ -48,9 +48,9 @@
|
||||||
"term.playlists": "播放列表",
|
"term.playlists": "播放列表",
|
||||||
"term.playlist": "播放列表",
|
"term.playlist": "播放列表",
|
||||||
"term.newPlaylist": "新播放列表",
|
"term.newPlaylist": "新播放列表",
|
||||||
"term.newPlaylistFolder": "新資料夾",
|
"term.newPlaylistFolder": "新播放列表資料夾",
|
||||||
"term.createNewPlaylist": "新增播放列表",
|
"term.createNewPlaylist": "新增播放列表",
|
||||||
"term.createNewPlaylistFolder": "新增資料夾",
|
"term.createNewPlaylistFolder": "新增播放列表資料夾",
|
||||||
"term.deletePlaylist": "你確認要刪除這個播放列表?",
|
"term.deletePlaylist": "你確認要刪除這個播放列表?",
|
||||||
"term.play": "播放",
|
"term.play": "播放",
|
||||||
"term.pause": "暫停",
|
"term.pause": "暫停",
|
||||||
|
@ -317,8 +317,8 @@
|
||||||
"settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling 記錄", // Option to Connect
|
"settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling 記錄", // Option to Connect
|
||||||
"settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble 延遲 (%)",
|
"settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble 延遲 (%)",
|
||||||
"settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 Last.fm 正在播放",
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 Last.fm 正在播放",
|
||||||
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除藝人推薦 (Last.fm)",
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (LastFM)",
|
||||||
//"settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)",
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (LastFM)",
|
||||||
// Refer to term.connect for the connect button
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
// Settings - Experimental
|
// Settings - Experimental
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"i18n.languageName": "繁體中文(台灣)", // name of language in native language
|
"i18n.languageName": "繁體中文(台灣)", // name of language in native language
|
||||||
"i18n.languageNameEnglish": "Trad. Chinese (Taiwan)", // name of language in English
|
"i18n.languageNameEnglish": "Trad. Chinese (Taiwan)", // name of language in English
|
||||||
"i18n.category": "main", // main = real language, fun = fun community languages
|
"i18n.category": "main", // main = real language, fun = fun community languages
|
||||||
"i18n.authors": "@maikirakiwi @jay900604 @kyw504100", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
"i18n.authors": "@maikirakiwi @jay900604 @kyw504100 @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space
|
||||||
|
|
||||||
// App info
|
// App info
|
||||||
"app.name": "Cider",
|
"app.name": "Cider",
|
||||||
|
@ -45,6 +45,11 @@
|
||||||
"term.podcasts": "Podcasts",
|
"term.podcasts": "Podcasts",
|
||||||
"term.playlists": "播放列表",
|
"term.playlists": "播放列表",
|
||||||
"term.playlist": "播放列表",
|
"term.playlist": "播放列表",
|
||||||
|
"term.newPlaylist": "新播放列表",
|
||||||
|
"term.newPlaylistFolder": "新播放列表資料夾",
|
||||||
|
"term.createNewPlaylist": "新增播放列表",
|
||||||
|
"term.createNewPlaylistFolder": "新增播放列表資料夾",
|
||||||
|
"term.deletePlaylist": "您確定要刪除此播放列表嗎?",
|
||||||
"term.play": "播放",
|
"term.play": "播放",
|
||||||
"term.pause": "暫停",
|
"term.pause": "暫停",
|
||||||
"term.previous": "上一首",
|
"term.previous": "上一首",
|
||||||
|
@ -55,7 +60,7 @@
|
||||||
"term.mute": "靜音",
|
"term.mute": "靜音",
|
||||||
"term.unmute": "取消靜音",
|
"term.unmute": "取消靜音",
|
||||||
"term.share": "分享",
|
"term.share": "分享",
|
||||||
"term.share.success": "已複製至剪貼簿",
|
"term.share.success": "已複製到剪貼簿",
|
||||||
"term.settings": "設定",
|
"term.settings": "設定",
|
||||||
"term.seeAll": "顯示全部",
|
"term.seeAll": "顯示全部",
|
||||||
"term.sortBy": "排序",
|
"term.sortBy": "排序",
|
||||||
|
@ -105,7 +110,7 @@
|
||||||
"term.clearAll": "清空",
|
"term.clearAll": "清空",
|
||||||
"term.recentStations": "最近收聽的廣播",
|
"term.recentStations": "最近收聽的廣播",
|
||||||
"term.language": "語言",
|
"term.language": "語言",
|
||||||
"term.noLyrics": "正在載入。。/ 無歌詞結果 / 純音樂",
|
"term.noLyrics": "正在載入... / 無歌詞結果 / 純音樂",
|
||||||
"term.copyright": "版權聲明",
|
"term.copyright": "版權聲明",
|
||||||
"term.rightsReserved": "保留所有權利。",
|
"term.rightsReserved": "保留所有權利。",
|
||||||
"term.sponsor": "贊助我們",
|
"term.sponsor": "贊助我們",
|
||||||
|
@ -283,13 +288,14 @@
|
||||||
"settings.option.connectivity.discordRPC": "Discord 動態", // Dropdown
|
"settings.option.connectivity.discordRPC": "Discord 動態", // Dropdown
|
||||||
"settings.option.connectivity.playbackNotifications": "歌曲播放通知", // Toggle
|
"settings.option.connectivity.playbackNotifications": "歌曲播放通知", // Toggle
|
||||||
// Refer to term.disabled for the disabled option
|
// Refer to term.disabled for the disabled option
|
||||||
"settings.header.connectivity.discordRPC.cider": "顯示正在玩 'Cider'",
|
"settings.header.connectivity.discordRPC.cider": "顯示正在使用 'Cider'",
|
||||||
"settings.header.connectivity.discordRPC.appleMusic": "顯示正在玩 'Apple Music'",
|
"settings.header.connectivity.discordRPC.appleMusic": "顯示正在使用 'Apple Music'",
|
||||||
"settings.option.connectivity.discordRPC.clearOnPause": "暫停時清除 Discord 動態", // Toggle
|
"settings.option.connectivity.discordRPC.clearOnPause": "暫停時清除 Discord 動態", // Toggle
|
||||||
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 記錄", // Option to Connect
|
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 記錄", // Option to Connect
|
||||||
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延遲 (%)",
|
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延遲 (%)",
|
||||||
"settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 LastFM 目前聆聽", // Toggle
|
"settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 LastFM 目前聆聽", // Toggle
|
||||||
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除藝人推薦 (LastFM)",
|
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (LastFM)",
|
||||||
|
"settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (LastFM)",
|
||||||
// Refer to term.connect for the connect button
|
// Refer to term.connect for the connect button
|
||||||
|
|
||||||
// Settings - Experimental
|
// Settings - Experimental
|
||||||
|
|
|
@ -44,6 +44,7 @@ export class BrowserWindow {
|
||||||
"pages/search",
|
"pages/search",
|
||||||
"pages/about",
|
"pages/about",
|
||||||
"pages/library-videos",
|
"pages/library-videos",
|
||||||
|
"pages/remote-pair",
|
||||||
"components/mediaitem-artwork",
|
"components/mediaitem-artwork",
|
||||||
"components/artwork-material",
|
"components/artwork-material",
|
||||||
"components/menu-panel",
|
"components/menu-panel",
|
||||||
|
@ -66,6 +67,7 @@ export class BrowserWindow {
|
||||||
"components/listennow-child",
|
"components/listennow-child",
|
||||||
"components/mediaitem-mvview-sp",
|
"components/mediaitem-mvview-sp",
|
||||||
"components/animatedartwork-view",
|
"components/animatedartwork-view",
|
||||||
|
"components/listitem-horizontal",
|
||||||
"components/lyrics-view",
|
"components/lyrics-view",
|
||||||
"components/fullscreen",
|
"components/fullscreen",
|
||||||
"components/miniplayer",
|
"components/miniplayer",
|
||||||
|
@ -525,7 +527,7 @@ export class BrowserWindow {
|
||||||
|
|
||||||
ipcMain.on('play', (_event, type, id) => {
|
ipcMain.on('play', (_event, type, id) => {
|
||||||
BrowserWindow.win.webContents.executeJavaScript(`
|
BrowserWindow.win.webContents.executeJavaScript(`
|
||||||
MusicKit.getInstance().setQueue({ ${type}: '${id}'}).then(function(queue) {
|
MusicKit.getInstance().setQueue({ ${type}: '${id}', parameters : {l : app.mklang}}).then(function(queue) {
|
||||||
MusicKit.getInstance().play();
|
MusicKit.getInstance().play();
|
||||||
});
|
});
|
||||||
`)
|
`)
|
||||||
|
@ -539,7 +541,7 @@ export class BrowserWindow {
|
||||||
|
|
||||||
ipcMain.on('get-remote-pair-url', (_event, _) => {
|
ipcMain.on('get-remote-pair-url', (_event, _) => {
|
||||||
let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`;
|
let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`;
|
||||||
BrowserWindow.win.webContents.send('send-remote-pair-url', url);
|
BrowserWindow.win.webContents.send('send-remote-pair-url', (`https://cider.sh/pair-remote?url=${Buffer.from(encodeURI(url)).toString('base64')}`).toString());
|
||||||
});
|
});
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
app.setUserActivity('com.CiderCollective.remote.pair', {
|
app.setUserActivity('com.CiderCollective.remote.pair', {
|
||||||
|
|
|
@ -33,6 +33,15 @@ export class Plugins {
|
||||||
if (fs.existsSync(this.userPluginsPath)) {
|
if (fs.existsSync(this.userPluginsPath)) {
|
||||||
fs.readdirSync(this.userPluginsPath).forEach(file => {
|
fs.readdirSync(this.userPluginsPath).forEach(file => {
|
||||||
if (file.endsWith('.ts') || file.endsWith('.js')) {
|
if (file.endsWith('.ts') || file.endsWith('.js')) {
|
||||||
|
if (!electron.app.isPackaged) {
|
||||||
|
const plugin = require(path.join(this.userPluginsPath, file)).default;
|
||||||
|
file = file.replace('.ts', '').replace('.js', '');
|
||||||
|
if (plugins[file] || plugin in plugins) {
|
||||||
|
console.log(`[${plugin.name}] Plugin already loaded / Duplicate Class Name`);
|
||||||
|
} else {
|
||||||
|
plugins[file] = new plugin(electron.app, utils.getStore());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const plugin = require(path.join(this.userPluginsPath, file));
|
const plugin = require(path.join(this.userPluginsPath, file));
|
||||||
file = file.replace('.ts', '').replace('.js', '');
|
file = file.replace('.ts', '').replace('.js', '');
|
||||||
if (plugins[file] || plugin in plugins) {
|
if (plugins[file] || plugin in plugins) {
|
||||||
|
@ -41,6 +50,8 @@ export class Plugins {
|
||||||
plugins[file] = new plugin(electron.app, utils.getStore());
|
plugins[file] = new plugin(electron.app, utils.getStore());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log('[PluginHandler] Loaded plugins:', Object.keys(plugins));
|
console.log('[PluginHandler] Loaded plugins:', Object.keys(plugins));
|
||||||
|
|
|
@ -61,6 +61,9 @@ export class wsapi {
|
||||||
electron.ipcMain.on('wsapi-returnLyrics', (_event: any, arg: any) => {
|
electron.ipcMain.on('wsapi-returnLyrics', (_event: any, arg: any) => {
|
||||||
this.returnLyrics(JSON.parse(arg));
|
this.returnLyrics(JSON.parse(arg));
|
||||||
});
|
});
|
||||||
|
electron.ipcMain.on('wsapi-returnvolumeMax', (_event: any, arg: any) => {
|
||||||
|
this.returnmaxVolume(JSON.parse(arg));
|
||||||
|
});
|
||||||
this.wss = new WebSocketServer({
|
this.wss = new WebSocketServer({
|
||||||
port: this.port,
|
port: this.port,
|
||||||
perMessageDeflate: {
|
perMessageDeflate: {
|
||||||
|
@ -162,6 +165,10 @@ export class wsapi {
|
||||||
this._win.webContents.executeJavaScript(`MusicKit.getInstance().stop()`);
|
this._win.webContents.executeJavaScript(`MusicKit.getInstance().stop()`);
|
||||||
response.message = "Stopped";
|
response.message = "Stopped";
|
||||||
break;
|
break;
|
||||||
|
case "volumeMax":
|
||||||
|
this._win.webContents.executeJavaScript(`wsapi.getmaxVolume()`);
|
||||||
|
response.message = "maxVolume";
|
||||||
|
break;
|
||||||
case "volume":
|
case "volume":
|
||||||
this._win.webContents.executeJavaScript(`MusicKit.getInstance().volume = ${parseFloat(data.volume)}`);
|
this._win.webContents.executeJavaScript(`MusicKit.getInstance().volume = ${parseFloat(data.volume)}`);
|
||||||
response.message = "Volume";
|
response.message = "Volume";
|
||||||
|
@ -295,4 +302,11 @@ export class wsapi {
|
||||||
client.send(JSON.stringify(response));
|
client.send(JSON.stringify(response));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
returnmaxVolume(vol: any) {
|
||||||
|
const response: standardResponse = {status: 0, data: vol, message: "OK", type: "maxVolume"};
|
||||||
|
this.clients.forEach(function each(client: any) {
|
||||||
|
client.send(JSON.stringify(response));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -41,10 +41,13 @@ app.on('ready', () => {
|
||||||
require('vue-devtools').install()
|
require('vue-devtools').install()
|
||||||
}
|
}
|
||||||
|
|
||||||
components.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
|
await components.whenReady();
|
||||||
const bw = new BrowserWindow()
|
const bw = new BrowserWindow()
|
||||||
const win = await bw.createWindow()
|
const win = await bw.createWindow()
|
||||||
|
|
||||||
|
console.log('[Cider][Widevine] Status:', components.status());
|
||||||
|
|
||||||
win.on("ready-to-show", () => {
|
win.on("ready-to-show", () => {
|
||||||
Cider.bwCreated();
|
Cider.bwCreated();
|
||||||
CiderPlug.callPlugins('onReady', win);
|
CiderPlug.callPlugins('onReady', win);
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default class LastFMPlugin {
|
||||||
private _app: any;
|
private _app: any;
|
||||||
private _lastfm: any;
|
private _lastfm: any;
|
||||||
private _store: any;
|
private _store: any;
|
||||||
|
private _timer: any;
|
||||||
|
|
||||||
private authenticateFromFile() {
|
private authenticateFromFile() {
|
||||||
let sessionData = require(this.sessionPath)
|
let sessionData = require(this.sessionPath)
|
||||||
|
@ -77,27 +78,29 @@ export default class LastFMPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async scrobbleSong(attributes: any) {
|
private scrobbleSong(attributes: any) {
|
||||||
await new Promise(resolve => setTimeout(resolve, Math.round(attributes.durationInMillis * (this._store.lastfm.scrobble_after / 100))));
|
if(this._timer) clearTimeout(this._timer);
|
||||||
|
var self = this;
|
||||||
|
this._timer = setTimeout(() => {
|
||||||
const currentAttributes = attributes;
|
const currentAttributes = attributes;
|
||||||
|
|
||||||
if (!this._lastfm || this._lastfm.cachedAttributes === attributes) {
|
if (!self._lastfm || self._lastfm.cachedAttributes === attributes) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._lastfm.cachedAttributes) {
|
if (self._lastfm.cachedAttributes) {
|
||||||
if (this._lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return;
|
if (self._lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentAttributes.status && currentAttributes === attributes) {
|
if (currentAttributes.status && currentAttributes === attributes) {
|
||||||
if (fs.existsSync(this.sessionPath)) {
|
if (fs.existsSync(this.sessionPath)) {
|
||||||
// Scrobble playing song.
|
// Scrobble playing song.
|
||||||
if (attributes.status === true) {
|
if (attributes.status === true) {
|
||||||
this._lastfm.track.scrobble({
|
self._lastfm.track.scrobble({
|
||||||
'artist': this.filterArtistName(attributes.artistName),
|
'artist': this.filterArtistName(attributes.artistName),
|
||||||
'track': attributes.name,
|
'track': attributes.name,
|
||||||
'album': attributes.albumName,
|
'album': attributes.albumName,
|
||||||
'albumArtist': this.filterArtistName(attributes.artistName),
|
'albumArtist': self.filterArtistName(attributes.artistName),
|
||||||
'timestamp': new Date().getTime() / 1000
|
'timestamp': new Date().getTime() / 1000
|
||||||
}, function (err: any, scrobbled: any) {
|
}, function (err: any, scrobbled: any) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -106,14 +109,14 @@ export default class LastFMPlugin {
|
||||||
|
|
||||||
console.log('[LastFM] Successfully scrobbled: ', scrobbled);
|
console.log('[LastFM] Successfully scrobbled: ', scrobbled);
|
||||||
});
|
});
|
||||||
this._lastfm.cachedAttributes = attributes
|
self._lastfm.cachedAttributes = attributes
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.authenticate();
|
self.authenticate();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return console.log('[LastFM] Did not add ', attributes.name, '—', this.filterArtistName(attributes.artistName), 'because now playing a other song.');
|
return console.log('[LastFM] Did not add ', attributes.name, '—', self.filterArtistName(attributes.artistName), 'because now playing a other song.');
|
||||||
}
|
}},Math.round(attributes.durationInMillis * (self._store.lastfm.scrobble_after / 100)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterArtistName(artist: any) {
|
private filterArtistName(artist: any) {
|
||||||
|
@ -234,8 +237,8 @@ export default class LastFMPlugin {
|
||||||
* @param attributes Music Attributes (attributes.status = current state)
|
* @param attributes Music Attributes (attributes.status = current state)
|
||||||
*/
|
*/
|
||||||
onPlaybackStateDidChange(attributes: object): void {
|
onPlaybackStateDidChange(attributes: object): void {
|
||||||
this.scrobbleSong(attributes)
|
|
||||||
this.updateNowPlayingSong(attributes)
|
this.updateNowPlayingSong(attributes)
|
||||||
|
this.scrobbleSong(attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,8 +249,8 @@ export default class LastFMPlugin {
|
||||||
if (!this._store.lastfm.filterLoop){
|
if (!this._store.lastfm.filterLoop){
|
||||||
this._lastfm.cachedNowPlayingAttributes = false;
|
this._lastfm.cachedNowPlayingAttributes = false;
|
||||||
this._lastfm.cachedAttributes = false}
|
this._lastfm.cachedAttributes = false}
|
||||||
this.scrobbleSong(attributes)
|
|
||||||
this.updateNowPlayingSong(attributes)
|
this.updateNowPlayingSong(attributes)
|
||||||
|
this.scrobbleSong(attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -101,7 +101,7 @@ export default class Thumbar {
|
||||||
{
|
{
|
||||||
label: 'Pause / Play',
|
label: 'Pause / Play',
|
||||||
accelerator: 'Space',
|
accelerator: 'Space',
|
||||||
click: () => this._win.webContents.executeJavaScript(`MusicKitInterop.playPause()`)
|
click: () => this._win.webContents.executeJavaScript(`app.SpacePause()`)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Next',
|
label: 'Next',
|
||||||
|
|
|
@ -15,11 +15,11 @@ const pad = (number: number, length: number) => String(number).padStart(length,
|
||||||
* @returns String
|
* @returns String
|
||||||
*/
|
*/
|
||||||
const convertTimeToString = (timeInSeconds: number) => {
|
const convertTimeToString = (timeInSeconds: number) => {
|
||||||
const timeInMinutes = timeInSeconds / 60;
|
const timeInMinutes = Math.floor(timeInSeconds / 60);
|
||||||
if (timeInMinutes < 60) {
|
if (timeInMinutes < 60) {
|
||||||
return timeInMinutes + ":" + pad(timeInSeconds % 60, 2);
|
return timeInMinutes + ":" + pad(Math.floor(timeInSeconds % 60), 2);
|
||||||
}
|
}
|
||||||
return timeInMinutes / 60 + ":" + pad(timeInMinutes % 60, 2) + ":" + pad(timeInSeconds % 60, 2);
|
return Math.floor(timeInMinutes / 60) + ":" + pad(Math.floor(timeInMinutes % 60), 2) + ":" + pad(Math.floor(timeInSeconds % 60), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WebNowPlaying {
|
export default class WebNowPlaying {
|
||||||
|
@ -28,19 +28,30 @@ export default class WebNowPlaying {
|
||||||
*/
|
*/
|
||||||
public name: string = 'WebNowPlaying';
|
public name: string = 'WebNowPlaying';
|
||||||
public description: string = 'Song info and playback control for the Rainmeter WebNowPlaying plugin.';
|
public description: string = 'Song info and playback control for the Rainmeter WebNowPlaying plugin.';
|
||||||
public version: string = '1.0.0';
|
public version: string = '1.0.1';
|
||||||
public author: string = 'Zennn <me@jozen.blue>';
|
public author: string = 'Zennn <me@jozen.blue>';
|
||||||
|
|
||||||
private _win: any;
|
private _win: any;
|
||||||
private ws: any = null;
|
private ws?: WebSocket;
|
||||||
private wsapiConn: any = null;
|
private wsapiConn?: WebSocket;
|
||||||
private playerName: string = 'Cider'/* Apple Music */;
|
private playerName: string = 'Cider';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
console.debug(`[Plugin][${this.name}] Loading Complete.`);
|
console.debug(`[Plugin][${this.name}] Loading Complete.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSongInfo(attributes: any) {
|
/**
|
||||||
|
* Blocks non-windows systems from running this plugin
|
||||||
|
* @private
|
||||||
|
* @decorator
|
||||||
|
*/
|
||||||
|
private static windowsOnly(_target: any, _propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
descriptor.value = () => void 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sendSongInfo(attributes: any) {
|
||||||
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
||||||
|
|
||||||
const fields = ['STATE', 'TITLE', 'ARTIST', 'ALBUM', 'COVER', 'DURATION', 'POSITION', 'VOLUME', 'REPEAT', 'SHUFFLE'];
|
const fields = ['STATE', 'TITLE', 'ARTIST', 'ALBUM', 'COVER', 'DURATION', 'POSITION', 'VOLUME', 'REPEAT', 'SHUFFLE'];
|
||||||
|
@ -79,9 +90,9 @@ export default class WebNowPlaying {
|
||||||
value = attributes.shuffleMode;
|
value = attributes.shuffleMode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.ws.send(`${field}:${value}`);
|
this.ws?.send(`${field}:${value}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||||
this.ws.send(`Error:Error updating ${field} for ${this.playerName}`);
|
this.ws.send(`Error:Error updating ${field} for ${this.playerName}`);
|
||||||
this.ws.send(`ErrorD:${error}`);
|
this.ws.send(`ErrorD:${error}`);
|
||||||
}
|
}
|
||||||
|
@ -89,13 +100,15 @@ export default class WebNowPlaying {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fireEvent(evt: any) {
|
private fireEvent(evt: WebSocket.MessageEvent) {
|
||||||
if (!evt.data) return;
|
if (!evt.data) return;
|
||||||
let value = '';
|
const data = <string>evt.data;
|
||||||
if (evt.data.split(/ (.+)/).length > 1) {
|
|
||||||
value = evt.data.split(/ (.+)/)[1];
|
let value: string = '';
|
||||||
|
if (data.split(/ (.+)/).length > 1) {
|
||||||
|
value = data.split(/ (.+)/)[1];
|
||||||
}
|
}
|
||||||
const eventName = evt.data.split(' ')[0].toLowerCase();
|
const eventName = data.split(' ')[0].toLowerCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
|
@ -132,7 +145,7 @@ export default class WebNowPlaying {
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.debug(error);
|
console.debug(error);
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||||
this.ws.send(`Error:Error sending event to ${this.playerName}`);
|
this.ws.send(`Error:Error sending event to ${this.playerName}`);
|
||||||
this.ws.send(`ErrorD:${error}`);
|
this.ws.send(`ErrorD:${error}`);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +155,8 @@ export default class WebNowPlaying {
|
||||||
/**
|
/**
|
||||||
* Runs on app ready
|
* Runs on app ready
|
||||||
*/
|
*/
|
||||||
onReady(win: any) {
|
@WebNowPlaying.windowsOnly
|
||||||
|
public onReady(win: any) {
|
||||||
this._win = win;
|
this._win = win;
|
||||||
|
|
||||||
// Connect to Rainmeter plugin and retry on disconnect.
|
// Connect to Rainmeter plugin and retry on disconnect.
|
||||||
|
@ -150,10 +164,10 @@ export default class WebNowPlaying {
|
||||||
try {
|
try {
|
||||||
this.ws = new WebSocket('ws://127.0.0.1:8974/');
|
this.ws = new WebSocket('ws://127.0.0.1:8974/');
|
||||||
let retry: NodeJS.Timeout;
|
let retry: NodeJS.Timeout;
|
||||||
this.ws.onopen = (() => {
|
this.ws.onopen = () => {
|
||||||
console.info('[WebNowPlaying] Connected to Rainmeter');
|
console.info('[WebNowPlaying] Connected to Rainmeter');
|
||||||
this.ws.send(`PLAYER:${this.playerName}`);
|
this.ws?.send(`PLAYER:${this.playerName}`);
|
||||||
}).bind(this);
|
};
|
||||||
|
|
||||||
this.ws.onclose = () => {
|
this.ws.onclose = () => {
|
||||||
clearTimeout(retry);
|
clearTimeout(retry);
|
||||||
|
@ -162,7 +176,7 @@ export default class WebNowPlaying {
|
||||||
|
|
||||||
this.ws.onerror = () => {
|
this.ws.onerror = () => {
|
||||||
clearTimeout(retry);
|
clearTimeout(retry);
|
||||||
this.ws.close();
|
this.ws?.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ws.onmessage = this.fireEvent?.bind(this);
|
this.ws.onmessage = this.fireEvent?.bind(this);
|
||||||
|
@ -181,8 +195,8 @@ export default class WebNowPlaying {
|
||||||
console.info('[WebNowPlaying] Connected to wsapi');
|
console.info('[WebNowPlaying] Connected to wsapi');
|
||||||
};
|
};
|
||||||
|
|
||||||
this.wsapiConn.onmessage = (evt: { data: string; }) => {
|
this.wsapiConn.onmessage = (evt: WebSocket.MessageEvent) => {
|
||||||
const response = JSON.parse(evt.data);
|
const response = JSON.parse(<string>evt.data);
|
||||||
if (response.type === 'playbackStateUpdate') {
|
if (response.type === 'playbackStateUpdate') {
|
||||||
this.sendSongInfo(response.data);
|
this.sendSongInfo(response.data);
|
||||||
}
|
}
|
||||||
|
@ -197,10 +211,11 @@ export default class WebNowPlaying {
|
||||||
/**
|
/**
|
||||||
* Runs on app stop
|
* Runs on app stop
|
||||||
*/
|
*/
|
||||||
onBeforeQuit() {
|
@WebNowPlaying.windowsOnly
|
||||||
|
public onBeforeQuit() {
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
this.ws.send('STATE:0');
|
this.ws.send('STATE:0');
|
||||||
this.ws.onclose = null; // disable onclose handler first to stop it from retrying
|
this.ws.onclose = () => void 0; // disable onclose handler first to stop it from retrying
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
}
|
}
|
||||||
if (this.wsapiConn) {
|
if (this.wsapiConn) {
|
||||||
|
@ -213,7 +228,8 @@ export default class WebNowPlaying {
|
||||||
* Runs on playback State Change
|
* Runs on playback State Change
|
||||||
* @param attributes Music Attributes (attributes.status = current state)
|
* @param attributes Music Attributes (attributes.status = current state)
|
||||||
*/
|
*/
|
||||||
onPlaybackStateDidChange(attributes: any) {
|
@WebNowPlaying.windowsOnly
|
||||||
|
public onPlaybackStateDidChange(attributes: any) {
|
||||||
this.sendSongInfo(attributes);
|
this.sendSongInfo(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +237,8 @@ export default class WebNowPlaying {
|
||||||
* Runs on song change
|
* Runs on song change
|
||||||
* @param attributes Music Attributes
|
* @param attributes Music Attributes
|
||||||
*/
|
*/
|
||||||
onNowPlayingItemDidChange(attributes: any) {
|
@WebNowPlaying.windowsOnly
|
||||||
|
public onNowPlayingItemDidChange(attributes: any) {
|
||||||
this.sendSongInfo(attributes);
|
this.sendSongInfo(attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ const MusicKitInterop = {
|
||||||
});
|
});
|
||||||
/** wsapi */
|
/** wsapi */
|
||||||
|
|
||||||
MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, () => {
|
MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, async () => {
|
||||||
|
await MusicKitInterop.modifyNamesOnLocale();
|
||||||
if (MusicKitInterop.filterTrack(MusicKitInterop.getAttributes(), false, true) || !app.cfg.lastfm.filterLoop) {
|
if (MusicKitInterop.filterTrack(MusicKitInterop.getAttributes(), false, true) || !app.cfg.lastfm.filterLoop) {
|
||||||
global.ipcRenderer.send('nowPlayingItemDidChange', MusicKitInterop.getAttributes());
|
global.ipcRenderer.send('nowPlayingItemDidChange', MusicKitInterop.getAttributes());
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,28 @@ const MusicKitInterop = {
|
||||||
console.warn(`[mediaPlaybackError] ${e}`);
|
console.warn(`[mediaPlaybackError] ${e}`);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
async modifyNamesOnLocale() {
|
||||||
|
if (app.mklang == '' || app.mklang == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mk = MusicKit.getInstance()
|
||||||
|
const nowPlayingItem = mk.nowPlayingItem;
|
||||||
|
if ((nowPlayingItem?._songId ?? nowPlayingItem?.songId) == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? nowPlayingItem?.id)
|
||||||
|
if (id != null) {
|
||||||
|
try{
|
||||||
|
const query = await mk.api.v3.music(`/v1${((nowPlayingItem?._songId ?? nowPlayingItem?.songId) != null) ? `/catalog/${mk.storefrontId}/` : `/me/library/`}songs/${id}?l=${app.mklang}`);
|
||||||
|
if (query?.data?.data[0]){
|
||||||
|
let attrs = query?.data?.data[0]?.attributes;
|
||||||
|
if (attrs?.name) { nowPlayingItem.attributes.name = attrs?.name ?? ''}
|
||||||
|
if (attrs?.albumName) { nowPlayingItem.attributes.albumName = attrs?.albumName ?? ''}
|
||||||
|
if (attrs?.artistName) { nowPlayingItem.attributes.artistName = attrs?.artistName ?? ''}
|
||||||
|
|
||||||
|
}} catch (e) { return;}
|
||||||
|
} else {return;}
|
||||||
|
},
|
||||||
getAttributes: function () {
|
getAttributes: function () {
|
||||||
const mk = MusicKit.getInstance()
|
const mk = MusicKit.getInstance()
|
||||||
const nowPlayingItem = mk.nowPlayingItem;
|
const nowPlayingItem = mk.nowPlayingItem;
|
||||||
|
@ -51,8 +73,8 @@ const MusicKitInterop = {
|
||||||
attributes.playParams = attributes?.playParams ?? {id: 'no-id-found'};
|
attributes.playParams = attributes?.playParams ?? {id: 'no-id-found'};
|
||||||
attributes.playParams.id = attributes?.playParams?.id ?? 'no-id-found';
|
attributes.playParams.id = attributes?.playParams?.id ?? 'no-id-found';
|
||||||
attributes.url = {
|
attributes.url = {
|
||||||
cider: `cider://play/s/${nowPlayingItem?._songId ?? 'no-id-found'}`,
|
cider: `cider://play/s/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}`,
|
||||||
appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? 'no-id-found'}`
|
appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}`
|
||||||
}
|
}
|
||||||
if (attributes.playParams.id === 'no-id-found') {
|
if (attributes.playParams.id === 'no-id-found') {
|
||||||
attributes.playParams.id = nowPlayingItem?.id ?? 'no-id-found';
|
attributes.playParams.id = nowPlayingItem?.id ?? 'no-id-found';
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
Vue.use(VueHorizontal);
|
||||||
Vue.use(VueObserveVisibility);
|
Vue.use(VueObserveVisibility);
|
||||||
var notyf = new Notyf();
|
var notyf = new Notyf();
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ const app = new Vue({
|
||||||
radio: {
|
radio: {
|
||||||
personal: []
|
personal: []
|
||||||
},
|
},
|
||||||
|
mklang : 'en',
|
||||||
webview: {
|
webview: {
|
||||||
url: "",
|
url: "",
|
||||||
title: "",
|
title: "",
|
||||||
|
@ -111,7 +113,8 @@ const app = new Vue({
|
||||||
"name": "0",
|
"name": "0",
|
||||||
"genre": "0",
|
"genre": "0",
|
||||||
"releaseDate": "0",
|
"releaseDate": "0",
|
||||||
"durationInMillis": "0"
|
"durationInMillis": "0",
|
||||||
|
"dateAdded": "0"
|
||||||
},
|
},
|
||||||
sorting: "name",
|
sorting: "name",
|
||||||
sortOrder: "asc",
|
sortOrder: "asc",
|
||||||
|
@ -292,7 +295,10 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
mainMenuVisibility(val) {
|
mainMenuVisibility(val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
(this.chrome.userinfo.id) ? this.chrome.menuOpened = !this.chrome.menuOpened : false
|
(this.mk.isAuthorized) ? this.chrome.menuOpened = !this.chrome.menuOpened : false;
|
||||||
|
if (!this.mk.isAuthorized){
|
||||||
|
this.mk.authorize()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.chrome.menuOpened = false
|
this.chrome.menuOpened = false
|
||||||
|
@ -308,11 +314,12 @@ const app = new Vue({
|
||||||
return text
|
return text
|
||||||
// stringTemplateParser('my name is {{name}} and age is {{age}}', {name: 'Tom', age:100})
|
// stringTemplateParser('my name is {{name}} and age is {{age}}', {name: 'Tom', age:100})
|
||||||
},
|
},
|
||||||
setLz(lang) {
|
async setLz(lang) {
|
||||||
if (lang == "") {
|
if (lang == "") {
|
||||||
lang = this.cfg.general.language
|
lang = this.cfg.general.language
|
||||||
}
|
}
|
||||||
this.lz = ipcRenderer.sendSync("get-i18n", lang)
|
this.lz = ipcRenderer.sendSync("get-i18n", lang)
|
||||||
|
this.mklang = await this.MKJSLang()
|
||||||
},
|
},
|
||||||
getLz(message) {
|
getLz(message) {
|
||||||
if (this.lz[message]) {
|
if (this.lz[message]) {
|
||||||
|
@ -328,7 +335,8 @@ const app = new Vue({
|
||||||
"name": app.getLz('term.sortBy.name'),
|
"name": app.getLz('term.sortBy.name'),
|
||||||
"genre": app.getLz('term.sortBy.genre'),
|
"genre": app.getLz('term.sortBy.genre'),
|
||||||
"releaseDate": app.getLz('term.sortBy.releaseDate'),
|
"releaseDate": app.getLz('term.sortBy.releaseDate'),
|
||||||
"durationInMillis": app.getLz('term.sortBy.duration')
|
"durationInMillis": app.getLz('term.sortBy.duration'),
|
||||||
|
"dateAdded": app.getLz('term.sortBy.dateAdded')
|
||||||
}
|
}
|
||||||
|
|
||||||
app.$data.library.albums.sortingOptions = {
|
app.$data.library.albums.sortingOptions = {
|
||||||
|
@ -568,6 +576,8 @@ const app = new Vue({
|
||||||
this.mk._services.timing.mode = 0
|
this.mk._services.timing.mode = 0
|
||||||
this.platform = ipcRenderer.sendSync('cider-platform');
|
this.platform = ipcRenderer.sendSync('cider-platform');
|
||||||
|
|
||||||
|
this.mklang = await this.MKJSLang()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Set profile name
|
// Set profile name
|
||||||
this.chrome.userinfo = (await app.mk.api.v3.music(`/v1/me/social-profile`)).data.data[0]
|
this.chrome.userinfo = (await app.mk.api.v3.music(`/v1/me/social-profile`)).data.data[0]
|
||||||
|
@ -633,7 +643,8 @@ const app = new Vue({
|
||||||
let kind = lastItem.attributes.playParams.kind;
|
let kind = lastItem.attributes.playParams.kind;
|
||||||
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind;
|
||||||
app.mk.setQueue({
|
app.mk.setQueue({
|
||||||
[truekind]: [lastItem.attributes.playParams.id]
|
[truekind]: [lastItem.attributes.playParams.id],
|
||||||
|
parameters : {l : app.mklang}
|
||||||
})
|
})
|
||||||
app.mk.mute()
|
app.mk.mute()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -686,7 +697,7 @@ const app = new Vue({
|
||||||
|
|
||||||
ipcRenderer.on('play', function(_event, mode, id) {
|
ipcRenderer.on('play', function(_event, mode, id) {
|
||||||
if (mode !== 'url'){
|
if (mode !== 'url'){
|
||||||
self.mk.setQueue({[mode]: id}).then(() => {
|
self.mk.setQueue({[mode]: id , parameters : {l : self.mklang}}).then(() => {
|
||||||
app.mk.play()
|
app.mk.play()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -723,7 +734,7 @@ const app = new Vue({
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
if (!previewURL) {
|
if (!previewURL) {
|
||||||
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/songs/${app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id}`).then((response) => {
|
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/songs/${app.mk.nowPlayingItem?._songId ?? (app.mk.nowPlayingItem["songId"] ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id)}`).then((response) => {
|
||||||
previewURL = response.data.data[0].attributes.previews[0].url
|
previewURL = response.data.data[0].attributes.previews[0].url
|
||||||
if (previewURL)
|
if (previewURL)
|
||||||
ipcRenderer.send('getPreviewURL', previewURL)
|
ipcRenderer.send('getPreviewURL', previewURL)
|
||||||
|
@ -792,6 +803,7 @@ const app = new Vue({
|
||||||
this.getBrowsePage();
|
this.getBrowsePage();
|
||||||
this.$forceUpdate()
|
this.$forceUpdate()
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
},
|
},
|
||||||
setTheme(theme = "") {
|
setTheme(theme = "") {
|
||||||
console.log(theme)
|
console.log(theme)
|
||||||
|
@ -1012,12 +1024,12 @@ const app = new Vue({
|
||||||
app.appRoute("collection-list")
|
app.appRoute("collection-list")
|
||||||
},
|
},
|
||||||
async showArtistView(artist, title, view) {
|
async showArtistView(artist, title, view) {
|
||||||
let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artist}/view/${view}`, {}, {includeResponseMeta: !0})).data
|
let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artist}/view/${view}?l=${this.mklang}`, {}, {includeResponseMeta: !0})).data
|
||||||
console.log(response)
|
console.log(response)
|
||||||
await this.showCollection(response, title, "artists")
|
await this.showCollection(response, title, "artists")
|
||||||
},
|
},
|
||||||
async showRecordLabelView(label, title, view) {
|
async showRecordLabelView(label, title, view) {
|
||||||
let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/record-labels/${label}/view/${view}`)).data
|
let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/record-labels/${label}/view/${view}?l=${this.mklang}`)).data
|
||||||
await this.showCollection(response, title, "record-labels")
|
await this.showCollection(response, title, "record-labels")
|
||||||
},
|
},
|
||||||
async showSearchView(term, group, title) {
|
async showSearchView(term, group, title) {
|
||||||
|
@ -1047,7 +1059,8 @@ const app = new Vue({
|
||||||
omit: {
|
omit: {
|
||||||
resource: ["autos"]
|
resource: ["autos"]
|
||||||
},
|
},
|
||||||
groups: group
|
groups: group,
|
||||||
|
l : this.mklang
|
||||||
}
|
}
|
||||||
let response = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${term}`, requestBody, {
|
let response = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${term}`, requestBody, {
|
||||||
includeResponseMeta: !0
|
includeResponseMeta: !0
|
||||||
|
@ -1098,7 +1111,8 @@ const app = new Vue({
|
||||||
"fields[playlists]": "curatorName,playlistType,name,artwork,url,playParams",
|
"fields[playlists]": "curatorName,playlistType,name,artwork,url,playParams",
|
||||||
"include[library-songs]": "catalog,artists,albums,playParams,name,artwork,url",
|
"include[library-songs]": "catalog,artists,albums,playParams,name,artwork,url",
|
||||||
"fields[catalog]": "artistUrl,albumUrl,url",
|
"fields[catalog]": "artistUrl,albumUrl,url",
|
||||||
"fields[songs]": "artistUrl,albumUrl,playParams,name,artwork,url,artistName,albumName,durationInMillis"
|
"fields[songs]": "artistUrl,albumUrl,playParams,name,artwork,url,artistName,albumName,durationInMillis",
|
||||||
|
l : this.mklang
|
||||||
}
|
}
|
||||||
if (!transient) {
|
if (!transient) {
|
||||||
this.playlists.loadingState = 0;
|
this.playlists.loadingState = 0;
|
||||||
|
@ -1126,7 +1140,8 @@ const app = new Vue({
|
||||||
"include[songs]": "albums",
|
"include[songs]": "albums",
|
||||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount",
|
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount",
|
||||||
"limit[artists:top-songs]": 20,
|
"limit[artists:top-songs]": 20,
|
||||||
"art[url]": "f"
|
"art[url]": "f",
|
||||||
|
l : this.mklang
|
||||||
}, {includeResponseMeta: !0})
|
}, {includeResponseMeta: !0})
|
||||||
console.log(artistData.data.data[0])
|
console.log(artistData.data.data[0])
|
||||||
this.artistPage.data = artistData.data.data[0]
|
this.artistPage.data = artistData.data.data[0]
|
||||||
|
@ -1321,7 +1336,7 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getNowPlayingItemDetailed(target) {
|
async getNowPlayingItemDetailed(target) {
|
||||||
let u = await app.mkapi(app.mk.nowPlayingItem.playParams.kind, (app.mk.nowPlayingItem.songId == -1), (app.mk.nowPlayingItem.songId != -1) ? app.mk.nowPlayingItem.songId : app.mk.nowPlayingItem["id"], {"include[songs]": "albums,artists"});
|
let u = await app.mkapi(app.mk.nowPlayingItem.playParams.kind, (app.mk.nowPlayingItem.songId == -1), (app.mk.nowPlayingItem.songId != -1) ? app.mk.nowPlayingItem.songId : app.mk.nowPlayingItem["id"], {"include[songs]": "albums,artists", l : app.mklang});
|
||||||
app.searchAndNavigate(u.data.data[0], target)
|
app.searchAndNavigate(u.data.data[0], target)
|
||||||
},
|
},
|
||||||
async searchAndNavigate(item, target) {
|
async searchAndNavigate(item, target) {
|
||||||
|
@ -1526,6 +1541,7 @@ const app = new Vue({
|
||||||
if (kind == "album" | kind == "albums") {
|
if (kind == "album" | kind == "albums") {
|
||||||
params["include"] = "tracks,artists,record-labels,catalog";
|
params["include"] = "tracks,artists,record-labels,catalog";
|
||||||
}
|
}
|
||||||
|
params['l'] = this.mklang;
|
||||||
try {
|
try {
|
||||||
a = await this.mkapi(kind.toString(), isLibrary, id.toString(), params, params2);
|
a = await this.mkapi(kind.toString(), isLibrary, id.toString(), params, params2);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1554,17 +1570,24 @@ const app = new Vue({
|
||||||
searchLibrarySongs() {
|
searchLibrarySongs() {
|
||||||
let self = this
|
let self = this
|
||||||
let prefs = this.cfg.libraryPrefs.songs
|
let prefs = this.cfg.libraryPrefs.songs
|
||||||
|
let albumAdded = self.library?.albums?.listing?.map(function(i){return {[i.id]: i.attributes?.dateAdded}})
|
||||||
|
let startTime = new Date().getTime()
|
||||||
function sortSongs() {
|
function sortSongs() {
|
||||||
// sort this.library.songs.displayListing by song.attributes[self.library.songs.sorting] in descending or ascending order based on alphabetical order and numeric order
|
// sort this.library.songs.displayListing by song.attributes[self.library.songs.sorting] in descending or ascending order based on alphabetical order and numeric order
|
||||||
// check if song.attributes[self.library.songs.sorting] is a number and if so, sort by number if not, sort by alphabetical order ignoring case
|
// check if song.attributes[self.library.songs.sorting] is a number and if so, sort by number if not, sort by alphabetical order ignoring case
|
||||||
self.library.songs.displayListing.sort((a, b) => {
|
self.library.songs.displayListing.sort((a, b) => {
|
||||||
let aa = a.attributes[prefs.sort]
|
let aa = a.attributes[prefs.sort]
|
||||||
let bb = b.attributes[prefs.sort]
|
let bb = b.attributes[prefs.sort]
|
||||||
if (self.library.songs.sorting == "genre") {
|
if (prefs.sort == "genre") {
|
||||||
aa = a.attributes.genreNames[0]
|
aa = a.attributes.genreNames[0]
|
||||||
bb = b.attributes.genreNames[0]
|
bb = b.attributes.genreNames[0]
|
||||||
}
|
}
|
||||||
|
if (prefs.sort == "dateAdded"){
|
||||||
|
let albumida = a.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z'
|
||||||
|
let albumidb = b.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z'
|
||||||
|
aa = startTime - new Date(((albumAdded.find(i => i[albumida]))?? [])[albumida] ?? '1970-01-01T00:01:01Z').getTime()
|
||||||
|
bb = startTime - new Date(((albumAdded.find(i => i[albumidb]))?? [])[albumidb] ?? '1970-01-01T00:01:01Z').getTime()
|
||||||
|
}
|
||||||
if (aa == null) {
|
if (aa == null) {
|
||||||
aa = ""
|
aa = ""
|
||||||
}
|
}
|
||||||
|
@ -1816,10 +1839,11 @@ const app = new Vue({
|
||||||
"fields[catalog]": "artistUrl,albumUrl",
|
"fields[catalog]": "artistUrl,albumUrl",
|
||||||
"fields[songs]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
"fields[songs]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
||||||
limit: 100,
|
limit: 100,
|
||||||
|
l: self.mklang
|
||||||
}
|
}
|
||||||
const safeparams = {
|
const safeparams = {
|
||||||
"platform": "web",
|
"platform": "web",
|
||||||
"limit": 80,
|
"limit": 80
|
||||||
}
|
}
|
||||||
self.library.songs.downloadState = 1
|
self.library.songs.downloadState = 1
|
||||||
if (downloaded == null) {
|
if (downloaded == null) {
|
||||||
|
@ -1919,6 +1943,7 @@ const app = new Vue({
|
||||||
"fields[catalog]": "artistUrl,albumUrl",
|
"fields[catalog]": "artistUrl,albumUrl",
|
||||||
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
"fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
||||||
limit: 100,
|
limit: 100,
|
||||||
|
l: self.mklang
|
||||||
}
|
}
|
||||||
const safeparams = {
|
const safeparams = {
|
||||||
platform: "web",
|
platform: "web",
|
||||||
|
@ -2028,6 +2053,7 @@ const app = new Vue({
|
||||||
// "fields[catalog]": "artistUrl,albumUrl",
|
// "fields[catalog]": "artistUrl,albumUrl",
|
||||||
// "fields[artists]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
// "fields[artists]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url",
|
||||||
limit: 100,
|
limit: 100,
|
||||||
|
l: self.mklang
|
||||||
}
|
}
|
||||||
const safeparams = {
|
const safeparams = {
|
||||||
include: "catalog",
|
include: "catalog",
|
||||||
|
@ -2118,12 +2144,12 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getLibrarySongs() {
|
async getLibrarySongs() {
|
||||||
let response = await this.mkapi("songs", true, "", {limit: 100}, {includeResponseMeta: !0})
|
let response = await this.mkapi("songs", true, "", {limit: 100, l : this.mklang}, {includeResponseMeta: !0})
|
||||||
this.library.songs.listing = response.data.data
|
this.library.songs.listing = response.data.data
|
||||||
this.library.songs.meta = response.data.meta
|
this.library.songs.meta = response.data.meta
|
||||||
},
|
},
|
||||||
async getLibraryAlbums() {
|
async getLibraryAlbums() {
|
||||||
let response = await this.mkapi("albums", true, "", {limit: 100}, {includeResponseMeta: !0})
|
let response = await this.mkapi("albums", true, "", {limit: 100, l : this.mklang}, {includeResponseMeta: !0})
|
||||||
this.library.albums.listing = response.data.data
|
this.library.albums.listing = response.data.data
|
||||||
this.library.albums.meta = response.data.meta
|
this.library.albums.meta = response.data.meta
|
||||||
},
|
},
|
||||||
|
@ -2157,7 +2183,8 @@ const app = new Vue({
|
||||||
"extend[stations]": ["airDate", "supportsAirTimeUpdates"],
|
"extend[stations]": ["airDate", "supportsAirTimeUpdates"],
|
||||||
"meta[stations]": "inflectionPoints",
|
"meta[stations]": "inflectionPoints",
|
||||||
types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells",
|
types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells",
|
||||||
platform: "web"
|
platform: "web",
|
||||||
|
l: this.mklang
|
||||||
}, {
|
}, {
|
||||||
includeResponseMeta: !0,
|
includeResponseMeta: !0,
|
||||||
reload: !0
|
reload: !0
|
||||||
|
@ -2186,7 +2213,8 @@ const app = new Vue({
|
||||||
"include[music-videos]": "artists",
|
"include[music-videos]": "artists",
|
||||||
extend: "editorialArtwork,artistUrl",
|
extend: "editorialArtwork,artistUrl",
|
||||||
"fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes",
|
"fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes",
|
||||||
"art[url]": "f"
|
"art[url]": "f",
|
||||||
|
l: this.mklang
|
||||||
});
|
});
|
||||||
this.browsepage = browse.data.data[0];
|
this.browsepage = browse.data.data[0];
|
||||||
this.browsepage.timestamp = Date.now()
|
this.browsepage.timestamp = Date.now()
|
||||||
|
@ -2203,7 +2231,8 @@ const app = new Vue({
|
||||||
try {
|
try {
|
||||||
this.radio.personal = (await app.mk.api.v3.music(`/v1/me/recent/radio-stations`, {
|
this.radio.personal = (await app.mk.api.v3.music(`/v1/me/recent/radio-stations`, {
|
||||||
"platform": "web",
|
"platform": "web",
|
||||||
"art[url]": "f"
|
"art[url]": "f",
|
||||||
|
l: this.mklang
|
||||||
})).data.data;
|
})).data.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
|
@ -2269,12 +2298,12 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadAMLyrics() {
|
loadAMLyrics() {
|
||||||
const songID = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem["_songId"] ?? -1 : -1;
|
const songID = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem["_songId"] ?? (this.mk.nowPlayingItem["songId"] ?? -1) : -1;
|
||||||
// this.getMXM( trackName, artistName, 'en', duration);
|
// this.getMXM( trackName, artistName, 'en', duration);
|
||||||
if (songID != -1) {
|
if (songID != -1) {
|
||||||
MusicKit.getInstance().api.lyric(songID)
|
this.mk.api.v3.music(`v1/catalog/${this.mk.storefrontId}/songs/${songID}/lyrics`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.lyricsMediaItem = response.attributes["ttml"]
|
this.lyricsMediaItem = response.data?.data[0]?.attributes["ttml"]
|
||||||
this.parseTTML()
|
this.parseTTML()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2300,7 +2329,7 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
|
|
||||||
async losslessBadge() {
|
async losslessBadge() {
|
||||||
const songID = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem["_songId"] ?? -1 : -1;
|
const songID = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem["_songId"] ?? (this.mk.nowPlayingItem["songId"] ?? -1) : -1;
|
||||||
if (app.cfg.advanced.ciderPPE && songID != -1) {
|
if (app.cfg.advanced.ciderPPE && songID != -1) {
|
||||||
/**let extendedAssets = await app.mk.api.song(songID, {extend : 'extendedAssetUrls'})
|
/**let extendedAssets = await app.mk.api.song(songID, {extend : 'extendedAssetUrls'})
|
||||||
if (extendedAssets.attributes.audioTraits.includes('lossless')) {*/
|
if (extendedAssets.attributes.audioTraits.includes('lossless')) {*/
|
||||||
|
@ -2385,7 +2414,7 @@ const app = new Vue({
|
||||||
const track = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.title ?? '' : '');
|
const track = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.title ?? '' : '');
|
||||||
const artist = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : '');
|
const artist = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : '');
|
||||||
const time = encodeURIComponent((this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1);
|
const time = encodeURIComponent((this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1);
|
||||||
const id = encodeURIComponent((this.mk.nowPlayingItem != null) ? app.mk.nowPlayingItem._songId ?? '' : '');
|
const id = encodeURIComponent((this.mk.nowPlayingItem != null) ? app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem["songId"] ?? '') : '');
|
||||||
let lrcfile = "";
|
let lrcfile = "";
|
||||||
let richsync = [];
|
let richsync = [];
|
||||||
const lang = app.cfg.lyrics.mxm_language // translation language
|
const lang = app.cfg.lyrics.mxm_language // translation language
|
||||||
|
@ -2694,7 +2723,8 @@ const app = new Vue({
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.mk.setQueue({
|
this.mk.setQueue({
|
||||||
[truekind]: [id]
|
[truekind]: [id],
|
||||||
|
parameters : {l : this.mklang}
|
||||||
}).then(function (queue) {
|
}).then(function (queue) {
|
||||||
MusicKit.getInstance().play()
|
MusicKit.getInstance().play()
|
||||||
})
|
})
|
||||||
|
@ -2734,7 +2764,8 @@ const app = new Vue({
|
||||||
app.mk.stop().then(() => {
|
app.mk.stop().then(() => {
|
||||||
if (item) {
|
if (item) {
|
||||||
app.mk.setQueue({
|
app.mk.setQueue({
|
||||||
[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id
|
[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id,
|
||||||
|
parameters : {l : app.mklang}
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
app.mk.play().then(() => {
|
app.mk.play().then(() => {
|
||||||
if (app.mk.shuffleMode == 1) {
|
if (app.mk.shuffleMode == 1) {
|
||||||
|
@ -2768,7 +2799,8 @@ const app = new Vue({
|
||||||
app.mk.stop().then(() => {
|
app.mk.stop().then(() => {
|
||||||
if (truekind == "playlists" && (id.startsWith("p.") || id.startsWith("pl.u"))) {
|
if (truekind == "playlists" && (id.startsWith("p.") || id.startsWith("pl.u"))) {
|
||||||
app.mk.setQueue({
|
app.mk.setQueue({
|
||||||
[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id
|
[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id,
|
||||||
|
parameters : {l : app.mklang}
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1).then(function () {
|
app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1).then(function () {
|
||||||
if ((app.showingPlaylist && app.showingPlaylist.id == id)) {
|
if ((app.showingPlaylist && app.showingPlaylist.id == id)) {
|
||||||
|
@ -2807,7 +2839,8 @@ const app = new Vue({
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.mk.setQueue({
|
this.mk.setQueue({
|
||||||
[truekind]: [id]
|
[truekind]: [id],
|
||||||
|
parameters : {l : this.mklang}
|
||||||
}).then(function (queue) {
|
}).then(function (queue) {
|
||||||
if (item && ((queue._itemIDs[childIndex] != item.id))) {
|
if (item && ((queue._itemIDs[childIndex] != item.id))) {
|
||||||
childIndex = queue._itemIDs.indexOf(item.id)
|
childIndex = queue._itemIDs.indexOf(item.id)
|
||||||
|
@ -2891,7 +2924,7 @@ const app = new Vue({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//this.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${this.search.term}`
|
//this.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${this.search.term}`
|
||||||
this.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${this.search.term}`, {
|
this.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${encodeURIComponent(this.search.term)}`, {
|
||||||
types: "activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels",
|
types: "activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels",
|
||||||
"relate[editorial-items]": "contents",
|
"relate[editorial-items]": "contents",
|
||||||
"include[editorial-items]": "contents",
|
"include[editorial-items]": "contents",
|
||||||
|
@ -2906,7 +2939,8 @@ const app = new Vue({
|
||||||
"art[url]": "c,f",
|
"art[url]": "c,f",
|
||||||
"omit[resource]": "autos",
|
"omit[resource]": "autos",
|
||||||
"platform": "web",
|
"platform": "web",
|
||||||
limit: 25
|
limit: 25,
|
||||||
|
l: this.mklang
|
||||||
}).then(function (results) {
|
}).then(function (results) {
|
||||||
results.data.results["meta"] = results.data.meta
|
results.data.results["meta"] = results.data.meta
|
||||||
self.search.results = results.data.results
|
self.search.results = results.data.results
|
||||||
|
@ -3122,7 +3156,7 @@ const app = new Vue({
|
||||||
quickPlay(query) {
|
quickPlay(query) {
|
||||||
let self = this
|
let self = this
|
||||||
MusicKit.getInstance().api.search(query, {limit: 2, types: 'songs'}).then(function (data) {
|
MusicKit.getInstance().api.search(query, {limit: 2, types: 'songs'}).then(function (data) {
|
||||||
MusicKit.getInstance().setQueue({song: data["songs"]['data'][0]["id"]}).then(function (queue) {
|
MusicKit.getInstance().setQueue({song: data["songs"]['data'][0]["id"], parameters : {l : app.mklang}}).then(function (queue) {
|
||||||
MusicKit.getInstance().play()
|
MusicKit.getInstance().play()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
self.$forceUpdate()
|
self.$forceUpdate()
|
||||||
|
@ -3379,7 +3413,7 @@ const app = new Vue({
|
||||||
"icon": "./assets/feather/share.svg",
|
"icon": "./assets/feather/share.svg",
|
||||||
"name": app.getLz('action.share'),
|
"name": app.getLz('action.share'),
|
||||||
"action": function () {
|
"action": function () {
|
||||||
app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ?? '').then(u => {
|
app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => {
|
||||||
app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3388,7 +3422,7 @@ const app = new Vue({
|
||||||
"icon": "./assets/feather/share.svg",
|
"icon": "./assets/feather/share.svg",
|
||||||
"name": `${app.getLz('action.share')} (song.link)`,
|
"name": `${app.getLz('action.share')} (song.link)`,
|
||||||
"action": function () {
|
"action": function () {
|
||||||
app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ?? '').then(u => {
|
app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => {
|
||||||
app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3568,6 +3602,54 @@ const app = new Vue({
|
||||||
darwinShare(url) {
|
darwinShare(url) {
|
||||||
ipcRenderer.send('share-menu', url)
|
ipcRenderer.send('share-menu', url)
|
||||||
},
|
},
|
||||||
|
arrayToChunk(arr, chunkSize) {
|
||||||
|
let R = [];
|
||||||
|
for (let i = 0, len = arr.length; i < len; i += chunkSize) {
|
||||||
|
R.push(arr.slice(i, i + chunkSize));
|
||||||
|
}
|
||||||
|
return R;
|
||||||
|
},
|
||||||
|
SpacePause() {
|
||||||
|
const elems = document.querySelectorAll('input');
|
||||||
|
for (elem of elems){
|
||||||
|
if (elem === document.activeElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.isDev) // disable in dev mode to keep my sanity
|
||||||
|
MusicKitInterop.playPause();
|
||||||
|
},
|
||||||
|
async MKJSLang(){
|
||||||
|
let u = this.cfg.general.language;
|
||||||
|
// use MusicKit.getInstance or crash
|
||||||
|
try {
|
||||||
|
item = await MusicKit.getInstance().api.v3.music(`v1/storefronts/${app.mk.storefrontId}`)
|
||||||
|
let langcodes = item.data.data[0].attributes.supportedLanguageTags;
|
||||||
|
if (langcodes) langcodes = langcodes.map(function (u) { return u.toLowerCase() })
|
||||||
|
console.log(langcodes)
|
||||||
|
let sellang = ""
|
||||||
|
if (u && langcodes.includes(u.toLowerCase().replace('_', "-"))) {
|
||||||
|
sellang = ((u.toLowerCase()).replace('_', "-"))
|
||||||
|
} else if (u && u.includes('_') && langcodes.includes(((u.toLowerCase()).replace('_', "-")).split("-")[0])) {
|
||||||
|
sellang = ((u.toLowerCase()).replace('_', "-")).split("-")[0]
|
||||||
|
}
|
||||||
|
if (sellang == "") sellang = (item.data.data[0].attributes.defaultLanguageTag).toLowerCase()
|
||||||
|
console.log(sellang)
|
||||||
|
return await sellang
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log('locale err', err)
|
||||||
|
let langcodes = ['af', 'sq', 'ar', 'eu', 'bg', 'be', 'ca', 'zh', 'zh-tw', 'zh-cn', 'zh-hk', 'zh-sg', 'hr', 'cs', 'da', 'nl', 'nl-be', 'en', 'en-us', 'en-eg', 'en-au', 'en-gb', 'en-ca', 'en-nz', 'en-ie', 'en-za', 'en-jm', 'en-bz', 'en-tt', 'en-001', 'et', 'fo', 'fa', 'fi', 'fr', 'fr-ca', 'gd', 'de', 'de-ch', 'el', 'he', 'hi', 'hu', 'is', 'id', 'it', 'ja', 'ko', 'lv', 'lt', 'mk', 'mt', 'no', 'nb', 'nn', 'pl', 'pt-br', 'pt', 'rm', 'ro', 'ru', 'sr', 'sk', 'sl', 'es', 'es-mx', 'es-419', 'sv', 'th', 'ts', 'tn', 'tr', 'uk', 'ur', 've', 'vi', 'xh', 'yi', 'zu', 'ms', 'iw', 'lo', 'tl', 'kk', 'ta', 'te', 'bn', 'ga', 'ht', 'la', 'pa', 'sa'];
|
||||||
|
let sellang = "en"
|
||||||
|
if (u && langcodes.includes(u.toLowerCase().replace('_', "-"))) {
|
||||||
|
sellang = ((u.toLowerCase()).replace('_', "-"))
|
||||||
|
} else if (u && u.includes('_') && langcodes.includes(((u.toLowerCase()).replace('_', "-")).split("-")[0])) {
|
||||||
|
sellang = ((u.toLowerCase()).replace('_', "-")).split("-")[0]
|
||||||
|
}
|
||||||
|
if (sellang.startsWith("en") && this.mk.storefrontId != "en-us") sellang = "en-gb"
|
||||||
|
return await sellang
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3692,7 +3774,7 @@ document.addEventListener('musickitloaded', function () {
|
||||||
function initMusicKit() {
|
function initMusicKit() {
|
||||||
let parsedJson = JSON.parse(this.responseText)
|
let parsedJson = JSON.parse(this.responseText)
|
||||||
MusicKit.configure({
|
MusicKit.configure({
|
||||||
developerToken: parsedJson.Key,
|
developerToken: parsedJson.token,
|
||||||
app: {
|
app: {
|
||||||
name: 'Apple Music',
|
name: 'Apple Music',
|
||||||
build: '1978.4.1',
|
build: '1978.4.1',
|
||||||
|
@ -3716,7 +3798,7 @@ document.addEventListener('musickitloaded', function () {
|
||||||
fallbackinitMusicKit()
|
fallbackinitMusicKit()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
request.open("GET", "https://api.cider.sh/");
|
request.open("GET", "https://api.cider.sh/v1/");
|
||||||
request.send();
|
request.send();
|
||||||
|
|
||||||
// check for widevine failure and reconfigure the instance.
|
// check for widevine failure and reconfigure the instance.
|
||||||
|
|
|
@ -81,14 +81,14 @@ const wsapi = {
|
||||||
|
|
||||||
},
|
},
|
||||||
playTrackById(id, kind = "song") {
|
playTrackById(id, kind = "song") {
|
||||||
MusicKit.getInstance().setQueue({ [kind]: id }).then(function (queue) {
|
MusicKit.getInstance().setQueue({ [kind]: id , parameters : {l : app.mklang}}).then(function (queue) {
|
||||||
MusicKit.getInstance().play()
|
MusicKit.getInstance().play()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
quickPlay(term) {
|
quickPlay(term) {
|
||||||
// Quick play by song name
|
// Quick play by song name
|
||||||
MusicKit.getInstance().api.search(term, { limit: 2, types: 'songs' }).then(function (data) {
|
MusicKit.getInstance().api.search(term, { limit: 2, types: 'songs' }).then(function (data) {
|
||||||
MusicKit.getInstance().setQueue({ song: data["songs"][0]["id"] }).then(function (queue) {
|
MusicKit.getInstance().setQueue({ song: data["songs"][0]["id"],parameters : {l : app.mklang} }).then(function (queue) {
|
||||||
MusicKit.getInstance().play()
|
MusicKit.getInstance().play()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -107,5 +107,8 @@ const wsapi = {
|
||||||
}else{
|
}else{
|
||||||
MusicKit.getInstance().repeatMode = 0
|
MusicKit.getInstance().repeatMode = 0
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getmaxVolume() {
|
||||||
|
ipcRenderer.send('wsapi-returnvolumeMax',JSON.stringify(app.cfg.audio.maxVolume));
|
||||||
}
|
}
|
||||||
}
|
}
|
434
src/renderer/js/smoothscroll.js
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
/* smoothscroll v0.4.4 - 2019 - Dustan Kasten, Jeremias Menichelli - MIT License */
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// polyfill
|
||||||
|
function polyfill() {
|
||||||
|
// aliases
|
||||||
|
var w = window;
|
||||||
|
var d = document;
|
||||||
|
|
||||||
|
// return if scroll behavior is supported and polyfill is not forced
|
||||||
|
if (
|
||||||
|
'scrollBehavior' in d.documentElement.style &&
|
||||||
|
w.__forceSmoothScrollPolyfill__ !== true
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// globals
|
||||||
|
var Element = w.HTMLElement || w.Element;
|
||||||
|
var SCROLL_TIME = 468;
|
||||||
|
|
||||||
|
// object gathering original scroll methods
|
||||||
|
var original = {
|
||||||
|
scroll: w.scroll || w.scrollTo,
|
||||||
|
scrollBy: w.scrollBy,
|
||||||
|
elementScroll: Element.prototype.scroll || scrollElement,
|
||||||
|
scrollIntoView: Element.prototype.scrollIntoView
|
||||||
|
};
|
||||||
|
|
||||||
|
// define timing method
|
||||||
|
var now =
|
||||||
|
w.performance && w.performance.now
|
||||||
|
? w.performance.now.bind(w.performance)
|
||||||
|
: Date.now;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicates if a the current browser is made by Microsoft
|
||||||
|
* @method isMicrosoftBrowser
|
||||||
|
* @param {String} userAgent
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function isMicrosoftBrowser(userAgent) {
|
||||||
|
var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
|
||||||
|
|
||||||
|
return new RegExp(userAgentPatterns.join('|')).test(userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IE has rounding bug rounding down clientHeight and clientWidth and
|
||||||
|
* rounding up scrollHeight and scrollWidth causing false positives
|
||||||
|
* on hasScrollableSpace
|
||||||
|
*/
|
||||||
|
var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* changes scroll position inside an element
|
||||||
|
* @method scrollElement
|
||||||
|
* @param {Number} x
|
||||||
|
* @param {Number} y
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function scrollElement(x, y) {
|
||||||
|
this.scrollLeft = x;
|
||||||
|
this.scrollTop = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns result of applying ease math function to a number
|
||||||
|
* @method ease
|
||||||
|
* @param {Number} k
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
function ease(k) {
|
||||||
|
return 0.5 * (1 - Math.cos(Math.PI * k));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicates if a smooth behavior should be applied
|
||||||
|
* @method shouldBailOut
|
||||||
|
* @param {Number|Object} firstArg
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function shouldBailOut(firstArg) {
|
||||||
|
if (
|
||||||
|
firstArg === null ||
|
||||||
|
typeof firstArg !== 'object' ||
|
||||||
|
firstArg.behavior === undefined ||
|
||||||
|
firstArg.behavior === 'auto' ||
|
||||||
|
firstArg.behavior === 'instant'
|
||||||
|
) {
|
||||||
|
// first argument is not an object/null
|
||||||
|
// or behavior is auto, instant or undefined
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof firstArg === 'object' && firstArg.behavior === 'smooth') {
|
||||||
|
// first argument is an object and behavior is smooth
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw error when behavior is not supported
|
||||||
|
throw new TypeError(
|
||||||
|
'behavior member of ScrollOptions ' +
|
||||||
|
firstArg.behavior +
|
||||||
|
' is not a valid value for enumeration ScrollBehavior.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicates if an element has scrollable space in the provided axis
|
||||||
|
* @method hasScrollableSpace
|
||||||
|
* @param {Node} el
|
||||||
|
* @param {String} axis
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function hasScrollableSpace(el, axis) {
|
||||||
|
if (axis === 'Y') {
|
||||||
|
return el.clientHeight + ROUNDING_TOLERANCE < el.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis === 'X') {
|
||||||
|
return el.clientWidth + ROUNDING_TOLERANCE < el.scrollWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicates if an element has a scrollable overflow property in the axis
|
||||||
|
* @method canOverflow
|
||||||
|
* @param {Node} el
|
||||||
|
* @param {String} axis
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function canOverflow(el, axis) {
|
||||||
|
var overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
|
||||||
|
|
||||||
|
return overflowValue === 'auto' || overflowValue === 'scroll';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicates if an element can be scrolled in either axis
|
||||||
|
* @method isScrollable
|
||||||
|
* @param {Node} el
|
||||||
|
* @param {String} axis
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function isScrollable(el) {
|
||||||
|
var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
|
||||||
|
var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
|
||||||
|
|
||||||
|
return isScrollableY || isScrollableX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds scrollable parent of an element
|
||||||
|
* @method findScrollableParent
|
||||||
|
* @param {Node} el
|
||||||
|
* @returns {Node} el
|
||||||
|
*/
|
||||||
|
function findScrollableParent(el) {
|
||||||
|
while (el !== d.body && isScrollable(el) === false) {
|
||||||
|
el = el.parentNode || el.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* self invoked function that, given a context, steps through scrolling
|
||||||
|
* @method step
|
||||||
|
* @param {Object} context
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function step(context) {
|
||||||
|
var time = now();
|
||||||
|
var value;
|
||||||
|
var currentX;
|
||||||
|
var currentY;
|
||||||
|
var elapsed = (time - context.startTime) / SCROLL_TIME;
|
||||||
|
|
||||||
|
// avoid elapsed times higher than one
|
||||||
|
elapsed = elapsed > 1 ? 1 : elapsed;
|
||||||
|
|
||||||
|
// apply easing to elapsed time
|
||||||
|
value = ease(elapsed);
|
||||||
|
|
||||||
|
currentX = context.startX + (context.x - context.startX) * value;
|
||||||
|
currentY = context.startY + (context.y - context.startY) * value;
|
||||||
|
|
||||||
|
context.method.call(context.scrollable, currentX, currentY);
|
||||||
|
|
||||||
|
// scroll more if we have not reached our destination
|
||||||
|
if (currentX !== context.x || currentY !== context.y) {
|
||||||
|
w.requestAnimationFrame(step.bind(w, context));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrolls window or element with a smooth behavior
|
||||||
|
* @method smoothScroll
|
||||||
|
* @param {Object|Node} el
|
||||||
|
* @param {Number} x
|
||||||
|
* @param {Number} y
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function smoothScroll(el, x, y) {
|
||||||
|
var scrollable;
|
||||||
|
var startX;
|
||||||
|
var startY;
|
||||||
|
var method;
|
||||||
|
var startTime = now();
|
||||||
|
|
||||||
|
// define scroll context
|
||||||
|
if (el === d.body) {
|
||||||
|
scrollable = w;
|
||||||
|
startX = w.scrollX || w.pageXOffset;
|
||||||
|
startY = w.scrollY || w.pageYOffset;
|
||||||
|
method = original.scroll;
|
||||||
|
} else {
|
||||||
|
scrollable = el;
|
||||||
|
startX = el.scrollLeft;
|
||||||
|
startY = el.scrollTop;
|
||||||
|
method = scrollElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll looping over a frame
|
||||||
|
step({
|
||||||
|
scrollable: scrollable,
|
||||||
|
method: method,
|
||||||
|
startTime: startTime,
|
||||||
|
startX: startX,
|
||||||
|
startY: startY,
|
||||||
|
x: x,
|
||||||
|
y: y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ORIGINAL METHODS OVERRIDES
|
||||||
|
// w.scroll and w.scrollTo
|
||||||
|
w.scroll = w.scrollTo = function() {
|
||||||
|
// avoid action when no arguments are passed
|
||||||
|
if (arguments[0] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid smooth behavior if not required
|
||||||
|
if (shouldBailOut(arguments[0]) === true) {
|
||||||
|
original.scroll.call(
|
||||||
|
w,
|
||||||
|
arguments[0].left !== undefined
|
||||||
|
? arguments[0].left
|
||||||
|
: typeof arguments[0] !== 'object'
|
||||||
|
? arguments[0]
|
||||||
|
: w.scrollX || w.pageXOffset,
|
||||||
|
// use top prop, second argument if present or fallback to scrollY
|
||||||
|
arguments[0].top !== undefined
|
||||||
|
? arguments[0].top
|
||||||
|
: arguments[1] !== undefined
|
||||||
|
? arguments[1]
|
||||||
|
: w.scrollY || w.pageYOffset
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
|
smoothScroll.call(
|
||||||
|
w,
|
||||||
|
d.body,
|
||||||
|
arguments[0].left !== undefined
|
||||||
|
? ~~arguments[0].left
|
||||||
|
: w.scrollX || w.pageXOffset,
|
||||||
|
arguments[0].top !== undefined
|
||||||
|
? ~~arguments[0].top
|
||||||
|
: w.scrollY || w.pageYOffset
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// w.scrollBy
|
||||||
|
w.scrollBy = function() {
|
||||||
|
// avoid action when no arguments are passed
|
||||||
|
if (arguments[0] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid smooth behavior if not required
|
||||||
|
if (shouldBailOut(arguments[0])) {
|
||||||
|
original.scrollBy.call(
|
||||||
|
w,
|
||||||
|
arguments[0].left !== undefined
|
||||||
|
? arguments[0].left
|
||||||
|
: typeof arguments[0] !== 'object' ? arguments[0] : 0,
|
||||||
|
arguments[0].top !== undefined
|
||||||
|
? arguments[0].top
|
||||||
|
: arguments[1] !== undefined ? arguments[1] : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
|
smoothScroll.call(
|
||||||
|
w,
|
||||||
|
d.body,
|
||||||
|
~~arguments[0].left + (w.scrollX || w.pageXOffset),
|
||||||
|
~~arguments[0].top + (w.scrollY || w.pageYOffset)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Element.prototype.scroll and Element.prototype.scrollTo
|
||||||
|
Element.prototype.scroll = Element.prototype.scrollTo = function() {
|
||||||
|
// avoid action when no arguments are passed
|
||||||
|
if (arguments[0] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid smooth behavior if not required
|
||||||
|
if (shouldBailOut(arguments[0]) === true) {
|
||||||
|
// if one number is passed, throw error to match Firefox implementation
|
||||||
|
if (typeof arguments[0] === 'number' && arguments[1] === undefined) {
|
||||||
|
throw new SyntaxError('Value could not be converted');
|
||||||
|
}
|
||||||
|
|
||||||
|
original.elementScroll.call(
|
||||||
|
this,
|
||||||
|
// use left prop, first number argument or fallback to scrollLeft
|
||||||
|
arguments[0].left !== undefined
|
||||||
|
? ~~arguments[0].left
|
||||||
|
: typeof arguments[0] !== 'object' ? ~~arguments[0] : this.scrollLeft,
|
||||||
|
// use top prop, second argument or fallback to scrollTop
|
||||||
|
arguments[0].top !== undefined
|
||||||
|
? ~~arguments[0].top
|
||||||
|
: arguments[1] !== undefined ? ~~arguments[1] : this.scrollTop
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = arguments[0].left;
|
||||||
|
var top = arguments[0].top;
|
||||||
|
|
||||||
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
|
smoothScroll.call(
|
||||||
|
this,
|
||||||
|
this,
|
||||||
|
typeof left === 'undefined' ? this.scrollLeft : ~~left,
|
||||||
|
typeof top === 'undefined' ? this.scrollTop : ~~top
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Element.prototype.scrollBy
|
||||||
|
Element.prototype.scrollBy = function() {
|
||||||
|
// avoid action when no arguments are passed
|
||||||
|
if (arguments[0] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid smooth behavior if not required
|
||||||
|
if (shouldBailOut(arguments[0]) === true) {
|
||||||
|
original.elementScroll.call(
|
||||||
|
this,
|
||||||
|
arguments[0].left !== undefined
|
||||||
|
? ~~arguments[0].left + this.scrollLeft
|
||||||
|
: ~~arguments[0] + this.scrollLeft,
|
||||||
|
arguments[0].top !== undefined
|
||||||
|
? ~~arguments[0].top + this.scrollTop
|
||||||
|
: ~~arguments[1] + this.scrollTop
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scroll({
|
||||||
|
left: ~~arguments[0].left + this.scrollLeft,
|
||||||
|
top: ~~arguments[0].top + this.scrollTop,
|
||||||
|
behavior: arguments[0].behavior
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Element.prototype.scrollIntoView
|
||||||
|
Element.prototype.scrollIntoView = function() {
|
||||||
|
// avoid smooth behavior if not required
|
||||||
|
if (shouldBailOut(arguments[0]) === true) {
|
||||||
|
original.scrollIntoView.call(
|
||||||
|
this,
|
||||||
|
arguments[0] === undefined ? true : arguments[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
|
var scrollableParent = findScrollableParent(this);
|
||||||
|
var parentRects = scrollableParent.getBoundingClientRect();
|
||||||
|
var clientRects = this.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (scrollableParent !== d.body) {
|
||||||
|
// reveal element inside parent
|
||||||
|
smoothScroll.call(
|
||||||
|
this,
|
||||||
|
scrollableParent,
|
||||||
|
scrollableParent.scrollLeft + clientRects.left - parentRects.left,
|
||||||
|
scrollableParent.scrollTop + clientRects.top - parentRects.top
|
||||||
|
);
|
||||||
|
|
||||||
|
// reveal parent in viewport unless is fixed
|
||||||
|
if (w.getComputedStyle(scrollableParent).position !== 'fixed') {
|
||||||
|
w.scrollBy({
|
||||||
|
left: parentRects.left,
|
||||||
|
top: parentRects.top,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// reveal element in viewport
|
||||||
|
w.scrollBy({
|
||||||
|
left: clientRects.left,
|
||||||
|
top: clientRects.top,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||||
|
// commonjs
|
||||||
|
module.exports = { polyfill: polyfill };
|
||||||
|
} else {
|
||||||
|
// global
|
||||||
|
polyfill();
|
||||||
|
}
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
1
src/renderer/js/vue-horizontal.js
Normal file
5033
src/renderer/less/bootstrap.less
vendored
|
@ -663,6 +663,7 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
||||||
|
|
||||||
.usermenu-container {
|
.usermenu-container {
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
z-index: 200001 !important;
|
||||||
#cmenu.container();
|
#cmenu.container();
|
||||||
|
|
||||||
.usermenu-body {
|
.usermenu-body {
|
||||||
|
@ -2745,11 +2746,13 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
padding: var(--contentInnerPadding);
|
padding: var(--contentInnerPadding);
|
||||||
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
|
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
|
||||||
|
|
||||||
|
&.itemContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: wrap;
|
flex-flow: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
.cd-mediaitem-square {
|
||||||
> .cd-mediaitem-square {
|
|
||||||
width: 220px;
|
width: 220px;
|
||||||
height: 260px;
|
height: 260px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@ -2763,6 +2766,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Library - Songs page
|
// Library - Songs page
|
||||||
.library-page {
|
.library-page {
|
||||||
|
@ -2977,7 +2981,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
padding-top: var(--navigationBarHeight);
|
padding-top: var(--navigationBarHeight);
|
||||||
|
|
||||||
.playlist-body {
|
.playlist-body {
|
||||||
padding: 0px var(--contentInnerPadding) 0px var(--contentInnerPadding);
|
padding: var(--contentInnerPadding) 2em;
|
||||||
margin-top: -75px;
|
margin-top: -75px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3445,7 +3449,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
|
|
||||||
.artist-body {
|
.artist-body {
|
||||||
padding: 0px var(--contentInnerPadding) 0px var(--contentInnerPadding);
|
padding: 0px var(--contentInnerPadding) 0px var(--contentInnerPadding);
|
||||||
margin-top: -140px;
|
margin: -140px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.animated > .artist-body {
|
&.animated > .artist-body {
|
||||||
|
@ -3566,7 +3570,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 1001;
|
z-index: 100001;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -3751,14 +3755,6 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
|
|
||||||
/* horizontal media scroller */
|
/* horizontal media scroller */
|
||||||
.cd-hmedia-scroller {
|
.cd-hmedia-scroller {
|
||||||
margin: 0 auto;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row;
|
|
||||||
overflow-x: scroll;
|
|
||||||
overflow-y: hidden;
|
|
||||||
height: 284px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
@ -3767,16 +3763,9 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
box-shadow: inset 0px 0px 10px 10px rgb(200 200 200 / 50%);
|
box-shadow: inset 0px 0px 10px 10px rgb(200 200 200 / 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.small {
|
|
||||||
overflow-x: overlay;
|
|
||||||
height: 210px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hmedia-scroller-card {
|
&.hmedia-scroller-card {
|
||||||
height: 370px;
|
|
||||||
|
|
||||||
.mediaitem-card {
|
.mediaitem-card {
|
||||||
margin: 12px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4047,7 +4036,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
.cd-mediaitem-square-sp {
|
.cd-mediaitem-square-sp {
|
||||||
--spcolor: var("");
|
--spcolor: var("");
|
||||||
width: 190px;
|
width: 190px;
|
||||||
height: 250px;
|
height: 245px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -4286,7 +4275,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
/* mediaitem-square */
|
/* mediaitem-square */
|
||||||
.cd-mediaitem-square {
|
.cd-mediaitem-square {
|
||||||
width: 220px;
|
width: 220px;
|
||||||
height: 260px;
|
height: 238px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -5425,26 +5414,19 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
|
|
||||||
// Cider App
|
// Cider App
|
||||||
|
|
||||||
|
.listitem-horizontal {
|
||||||
|
.cd-mediaitem-list-item {
|
||||||
|
width: 350px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mediaitem-list-item__grid {
|
.mediaitem-list-item__grid {
|
||||||
overflow-x: overlay;
|
|
||||||
overflow-y: hidden;
|
|
||||||
background: rgba(200, 200, 200, 0.05);
|
background: rgba(200, 200, 200, 0.05);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: var(--contentInnerPadding);
|
padding: var(--contentInnerPadding);
|
||||||
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
|
box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
|
||||||
height: 300px;
|
width: 100%;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.grid-body {
|
|
||||||
display: grid;
|
|
||||||
grid-auto-flow: column dense;
|
|
||||||
grid-template-rows: auto auto auto auto;
|
|
||||||
grid-gap: 0 6px;
|
|
||||||
padding: 2px 0;
|
|
||||||
justify-content: left;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cd-mediaitem-list-item {
|
.cd-mediaitem-list-item {
|
||||||
width: 350px;
|
width: 350px;
|
||||||
|
|
|
@ -159,5 +159,11 @@
|
||||||
<cider-applecurator :data="appleCurator"></cider-applecurator>
|
<cider-applecurator :data="appleCurator"></cider-applecurator>
|
||||||
</template>
|
</template>
|
||||||
</transition>
|
</transition>
|
||||||
|
<!-- Library - Library Videos -->
|
||||||
|
<transition name="wpfade">
|
||||||
|
<template v-if="page == 'remote-pair'">
|
||||||
|
<remote-pair></remote-pair>
|
||||||
|
</template>
|
||||||
|
</transition>
|
||||||
|
|
||||||
</div>
|
</div>
|
|
@ -93,12 +93,8 @@
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
<button class="usermenu-item" @click="appRoute('remote-pair')">
|
||||||
<div class="row nopadding">
|
|
||||||
<div class="col nopadding">
|
|
||||||
<span class="usermenu-item-icon"><%- include("../svg/smartphone.svg") %></span>
|
<span class="usermenu-item-icon"><%- include("../svg/smartphone.svg") %></span>
|
||||||
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
|
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="usermenu-item" v-if="cfg.advanced.AudioContext"
|
<button class="usermenu-item" v-if="cfg.advanced.AudioContext"
|
||||||
@click="modals.audioSettings = true">
|
@click="modals.audioSettings = true">
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="name">{{app.getLz('term.equalizer')}}</div>
|
<div class="name">{{app.getLz('term.equalizer')}}</div>
|
||||||
</button>
|
</button>
|
||||||
<button class="playlist-item"
|
<button class="playlist-item"
|
||||||
@click="openSpacialAudio()" style="width:100%;">
|
@click="openSpatialAudio()" style="width:100%;">
|
||||||
<div class="icon"><%- include("../svg/speaker.svg") %></div>
|
<div class="icon"><%- include("../svg/speaker.svg") %></div>
|
||||||
<div class="name">{{app.getLz('settings.option.audio.enableAdvancedFunctionality.audioSpatialization')}}</div>
|
<div class="name">{{app.getLz('settings.option.audio.enableAdvancedFunctionality.audioSpatialization')}}</div>
|
||||||
</button>
|
</button>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
app.modals.equalizer = true
|
app.modals.equalizer = true
|
||||||
app.modals.audioSettings = false
|
app.modals.audioSettings = false
|
||||||
},
|
},
|
||||||
openSpacialAudio() {
|
openSpatialAudio() {
|
||||||
if(app.cfg.audio.spatial) {
|
if(app.cfg.audio.spatial) {
|
||||||
app.modals.spatialProperties = true
|
app.modals.spatialProperties = true
|
||||||
app.modals.audioSettings = false
|
app.modals.audioSettings = false
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
<div class="modal-title">{{$root.getLz('term.equalizer')}}</div>
|
||||||
<button class="close-btn" @click="close()"></button>
|
<button class="close-btn" @click="close()"></button>
|
||||||
<div class="md-option-segment md-option-segment_auto">
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
<select class="md-select" style="width:220px;text-align:center;margin-right:19.75em" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
<select class="md-select" style="width:220px;text-align:center;margin-right:245px" v-model="$root.cfg.audio.equalizer.preset" v-on:change="changePreset($root.cfg.audio.equalizer.preset)">
|
||||||
<optgroup label="User Presets">
|
<optgroup label="User Presets">
|
||||||
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
|
<option v-for="preset in $root.cfg.audio.equalizer.presets" :value="preset.preset">{{preset.name}}</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
|
|
43
src/renderer/views/components/listitem-horizontal.ejs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<script type="text/x-template" id="listitem-horizontal">
|
||||||
|
<div class="listitem-horizontal">
|
||||||
|
<vue-horizontal>
|
||||||
|
<div v-for="items in itemPages">
|
||||||
|
<mediaitem-list-item
|
||||||
|
v-for="(song, index) in items"
|
||||||
|
:index="song.index"
|
||||||
|
:item="song"></mediaitem-list-item>
|
||||||
|
</div>
|
||||||
|
</vue-horizontal>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('listitem-horizontal', {
|
||||||
|
template: '#listitem-horizontal',
|
||||||
|
name: "listitem-horizontal",
|
||||||
|
props: {
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
itemPages: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// give every item an id
|
||||||
|
this.items.forEach(function (item, index) {
|
||||||
|
item.id = index;
|
||||||
|
});
|
||||||
|
// split items into pages
|
||||||
|
this.itemPages = app.arrayToChunk(this.items, 4);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sayHello: function () {
|
||||||
|
alert('Hello world!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -16,16 +16,19 @@
|
||||||
<template v-if="isVisible">
|
<template v-if="isVisible">
|
||||||
<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'}">
|
||||||
<button @click="addToLibrary()" v-if="!addedToLibrary">
|
<button @click="addToLibrary()" v-if="!addedToLibrary && (showIndex == false ||(showIndex == true && showIndexPlaylist != false))">
|
||||||
<div class="svg-icon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
|
<div class="svg-icon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
|
||||||
</button>
|
</button>
|
||||||
|
<button v-else-if='!(showArtwork == true && (showIndex == false ||(showIndex == true && showIndexPlaylist != false)))' @click="playTrack()" style="width: 44px;margin-left: -11px;">
|
||||||
|
<%- include("../svg/play.svg") %>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!(app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id ))) && showIndex" :style="{display: ((showIndex && !showInLibrary) ? 'block' : 'none'), 'margin-left':'11px'}">
|
<div v-if="!(app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id )) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id ))) && showIndex" :style="{display: ((showIndex && !showInLibrary) ? 'block' : 'none'), 'margin-left':'11px'}">
|
||||||
<div>
|
<div>
|
||||||
<div>{{ (item.attributes && !showIndexPlaylist) ? (item.attributes.trackNumber ?? '') : ((index * 1 + 1 ) ?? '')}}</div>
|
<div>{{ (item.attributes && !showIndexPlaylist) ? (item.attributes.trackNumber ?? '') : ((index * 1 + 1 ) ?? '')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.id ) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id))" :style="{display: (showInLibrary ? 'none' : 'block')}">
|
<div v-if="app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id )) == item.attributes.playParams.id) || (app.mk.nowPlayingItem.id == item.id))" :style="{display: (showInLibrary ? 'none' : 'block')}">
|
||||||
<div class="loadbar-sound"></div>
|
<div class="loadbar-sound"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -528,7 +531,7 @@
|
||||||
array[j] = temp;
|
array[j] = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.mk.setQueue({ [truekind]: [item.attributes.playParams.id ?? item.id] }).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) {
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
<script type="text/x-template" id="mediaitem-scroller-horizontal-large">
|
||||||
<div class="cd-hmedia-scroller">
|
<vue-horizontal>
|
||||||
<template >
|
|
||||||
<mediaitem-square :item="item"
|
<mediaitem-square :item="item"
|
||||||
v-for="item in items"></mediaitem-square>
|
v-for="item in items"></mediaitem-square>
|
||||||
</template>
|
</vue-horizontal>
|
||||||
</div>
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal-mvview">
|
<script type="text/x-template" id="mediaitem-scroller-horizontal-mvview">
|
||||||
<div class="cd-hmedia-scroller">
|
<vue-horizontal>
|
||||||
<template v-if="browsesp">
|
<template v-if="browsesp">
|
||||||
<mediaitem-mvview-sp
|
<mediaitem-mvview-sp
|
||||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
:imagesize="imagesize"
|
:imagesize="imagesize"
|
||||||
v-for="item in items"></mediaitem-square>
|
v-for="item in items"></mediaitem-square>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</vue-horizontal>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
<script type="text/x-template" id="mediaitem-scroller-horizontal-sp">
|
||||||
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
<div class="cd-hmedia-scroller hmedia-scroller-card">
|
||||||
|
<vue-horizontal>
|
||||||
<template>
|
<template>
|
||||||
<mediaitem-square kind="card" :item="item" size="300"
|
<mediaitem-square kind="card" :item="item" size="300"
|
||||||
v-for="item in items"></mediaitem-square>
|
v-for="item in items"></mediaitem-square>
|
||||||
</template>
|
</template>
|
||||||
|
</vue-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<script type="text/x-template" id="mediaitem-scroller-horizontal">
|
<script type="text/x-template" id="mediaitem-scroller-horizontal">
|
||||||
<template>
|
<vue-horizontal>
|
||||||
<div class="cd-hmedia-scroller" :class="kind">
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<mediaitem-square :kind="kind" :item="item"
|
<mediaitem-square :kind="kind" :item="item" v-for="item in items"></mediaitem-square>
|
||||||
v-for="item in items"></mediaitem-square>
|
</vue-horizontal>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async getHistory() {
|
async getHistory() {
|
||||||
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`)
|
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l : this.$root.mklang})
|
||||||
this.history = history.data.data
|
this.history = history.data.data
|
||||||
},
|
},
|
||||||
select(e, position) {
|
select(e, position) {
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
<link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>
|
<link rel="stylesheet/less" type="text/css" id="userTheme" href="themes/default.less"/>
|
||||||
<script src="./js/less.js"></script>
|
<script src="./js/less.js"></script>
|
||||||
<script src="<%- (env.dev ? "./js/vue.js" : "./js/vue.dev.js") %>"></script>
|
<script src="<%- (env.dev ? "./js/vue.js" : "./js/vue.dev.js") %>"></script>
|
||||||
|
<script src="./js/vue-horizontal.js"></script>
|
||||||
|
<script src="./js/smoothscroll.js"></script>
|
||||||
<script src="./js/vuex.min.js"></script>
|
<script src="./js/vuex.min.js"></script>
|
||||||
<script src="./js/sortable.min.js"></script>
|
<script src="./js/sortable.min.js"></script>
|
||||||
<script src="./js/vue-observe-visibility.min.js"></script>
|
<script src="./js/vue-observe-visibility.min.js"></script>
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
<h3>{{app.getLz('home.followedArtists')}}</h3>
|
<h3>{{app.getLz('home.followedArtists')}}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="well">
|
<vue-horizontal>
|
||||||
<mediaitem-scroller-horizontal>
|
|
||||||
<div v-for="artist in artists" style="margin: 6px;">
|
<div v-for="artist in artists" style="margin: 6px;">
|
||||||
<mediaitem-square :item="artist" kind="small"></mediaitem-square>
|
<mediaitem-square :item="artist" kind="small"></mediaitem-square>
|
||||||
<button @click="unfollow(artist.id)" class="md-btn md-btn-glyph" style="display:flex;">
|
<button @click="unfollow(artist.id)" class="md-btn md-btn-glyph" style="display:flex;">
|
||||||
|
@ -18,8 +17,7 @@
|
||||||
</div> {{app.getLz('action.unfollow')}}
|
</div> {{app.getLz('action.unfollow')}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</mediaitem-scroller-horizontal>
|
</vue-horizontal>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +78,7 @@
|
||||||
let self = this
|
let self = this
|
||||||
this.artists = []
|
this.artists = []
|
||||||
this.artistFeed = []
|
this.artistFeed = []
|
||||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`).then(artistData => {
|
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`,{ l : this.$root.mklang}).then(artistData => {
|
||||||
artistData.data.data.forEach(item => {
|
artistData.data.data.forEach(item => {
|
||||||
self.artists.push(item)
|
self.artists.push(item)
|
||||||
if (item.views["latest-release"].data.length != 0) {
|
if (item.views["latest-release"].data.length != 0) {
|
||||||
|
|
|
@ -57,9 +57,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="artist-body">
|
<div class="artist-body">
|
||||||
<div class="row well">
|
<div class="row well">
|
||||||
<div class="col">
|
<div class="col-sm-3" v-if="data.views['latest-release'].data.length != 0">
|
||||||
<div class="row">
|
|
||||||
<div class="col-auto" v-if="data.views['latest-release'].data.length != 0">
|
|
||||||
<h3>{{app.getLz('term.latestReleases')}}</h3>
|
<h3>{{app.getLz('term.latestReleases')}}</h3>
|
||||||
<div style="width: auto;margin: 0 auto;">
|
<div style="width: auto;margin: 0 auto;">
|
||||||
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
|
<mediaitem-square kind="card" v-for="song in data.views['latest-release'].data"
|
||||||
|
@ -67,7 +65,7 @@
|
||||||
</mediaitem-square>
|
</mediaitem-square>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col" v-if="data.views['top-songs']">
|
<div class="col-sm-9" v-if="data.views['top-songs']">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col" style="padding:0;">
|
<div class="col" style="padding:0;">
|
||||||
<h3>{{app.getLz('term.topSongs')}}</h3>
|
<h3>{{app.getLz('term.topSongs')}}</h3>
|
||||||
|
@ -76,16 +74,15 @@
|
||||||
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">{{app.getLz('term.seeAll')}}</button>
|
<button class="cd-btn-seeall" @click="app.showArtistView(data.id, data.attributes.name + ' - Top Songs', 'top-songs')">{{app.getLz('term.seeAll')}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col flex-center" style="padding:0;">
|
||||||
<div class="mediaitem-list-item__grid">
|
<div class="mediaitem-list-item__grid">
|
||||||
<div class="grid-body">
|
<listitem-horizontal :items="data.views['top-songs'].data.limit(16)">
|
||||||
<mediaitem-list-item
|
</listitem-horizontal>
|
||||||
v-for="(song, index) in data.views['top-songs'].data.limit(16)"
|
|
||||||
:index="index"
|
|
||||||
:item="song"></mediaitem-list-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row well">
|
<div class="row well">
|
||||||
|
|
|
@ -169,10 +169,12 @@
|
||||||
<h3>{{ data.views[view].attributes.title }}</h3>
|
<h3>{{ data.views[view].attributes.title }}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="row" >
|
||||||
|
<div class="col">
|
||||||
<mediaitem-scroller-horizontal :items="data.views[view].data"></mediaitem-scroller-horizontal>
|
<mediaitem-scroller-horizontal :items="data.views[view].data"></mediaitem-scroller-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -287,7 +289,7 @@
|
||||||
this.confirm = false
|
this.confirm = false
|
||||||
},
|
},
|
||||||
async removeFromLibrary(id) {
|
async removeFromLibrary(id) {
|
||||||
const params = {"fields[somgs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"};
|
const params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library"};
|
||||||
var id = this.data.id ?? this.data.attributes.playParams.id
|
var id = this.data.id ?? this.data.attributes.playParams.id
|
||||||
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
const res = await app.mkapi(this.data.attributes.playParams.kind ?? this.data.type, this.data.attributes.playParams.isLibrary ?? false, this.data.attributes.playParams.id ?? this.data.id, params);
|
||||||
if (res.data.data[0] && res.data.data[0].relationships && res.data.data[0].relationships.library && res.data.data[0].relationships.library.data && res.data.data[0].relationships.library.data.length > 0) {
|
if (res.data.data[0] && res.data.data[0].relationships && res.data.data[0].relationships.library && res.data.data[0].relationships.library.data && res.data.data[0].relationships.library.data.length > 0) {
|
||||||
|
@ -478,7 +480,7 @@
|
||||||
|
|
||||||
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(function () {
|
||||||
app.mk.setQueue({[truekind]: [id]}).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) {
|
||||||
let u = query.slice(100);
|
let u = query.slice(100);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script type="text/x-template" id="cider-collection-list">
|
<script type="text/x-template" id="cider-collection-list">
|
||||||
<div class="content-inner collection-page">
|
<div class="content-inner collection-page">
|
||||||
<h3 class="header-text" v-observe-visibility="{callback: headerVisibility}">{{ title }}</h3>
|
<h3 class="header-text" v-observe-visibility="{callback: headerVisibility}">{{ title }}</h3>
|
||||||
<div v-if="data['data'] != 'null'" class="well">
|
<div v-if="data['data'] != 'null'" class="well itemContainer">
|
||||||
<template v-for="(item, key) in data.data">
|
<template v-for="(item, key) in data.data">
|
||||||
<template v-if="item.type == 'artists'">
|
<template v-if="item.type == 'artists'">
|
||||||
<mediaitem-square :item="item"></mediaitem-square>
|
<mediaitem-square :item="item"></mediaitem-square>
|
||||||
|
@ -14,8 +14,7 @@
|
||||||
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
<mediaitem-square v-else :item="item" :type="getKind(item)"></mediaitem-square>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<button v-if="triggerEnabled" style="opacity:0;height: 32px;"
|
<button v-if="triggerEnabled" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
||||||
v-observe-visibility="{callback: visibilityChanged}">{{this.app.getLz('term.showMore')}}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<transition name="fabfade">
|
<transition name="fabfade">
|
||||||
|
@ -23,7 +22,9 @@
|
||||||
<%- include("../svg/arrow-up.svg") %>
|
<%- include("../svg/arrow-up.svg") %>
|
||||||
</button>
|
</button>
|
||||||
</transition>
|
</transition>
|
||||||
<div class="well" v-show="loading"><div class="spinner"></div></div>
|
<div class="well itemContainer" v-show="loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
<div v-if="page == 'main'">
|
<div v-if="page == 'main'">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="row nopadding">
|
<div class="row">
|
||||||
<div class="col nopadding">
|
<div class="col nopadding">
|
||||||
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
<h3>{{app.getLz('home.recentlyPlayed')}}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto nopadding flex-center">
|
<div class="col-auto nopadding flex-center">
|
||||||
<button class="cd-btn-seeall" @click="seeAllHistory()">{{app.getLz('term.seeAll')}}</button>
|
<button class="cd-btn-seeall" @click="seeAllHistory()">{{app.getLz('term.history')}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="well artistfeed-well">
|
<div class="well artistfeed-well">
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="row nopadding">
|
<div class="row">
|
||||||
<div class="col nopadding">
|
<div class="col nopadding">
|
||||||
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
<h3>{{app.getLz('home.artistsFeed')}}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,9 +53,8 @@
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
<h3>{{app.getLz('home.madeForYou')}}</h3>
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<template v-if="isSectionReady('madeForYou')">
|
<mediaitem-scroller-horizontal :items="madeForYou" v-if="isSectionReady('madeForYou')">
|
||||||
<mediaitem-square kind="small" v-for="item in madeForYou" :item="item"></mediaitem-square>
|
</mediaitem-scroller-horizontal>
|
||||||
</template>
|
|
||||||
<div class="spinner" v-else></div>
|
<div class="spinner" v-else></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,10 +70,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<template v-if="isSectionReady('friendsListeningTo')">
|
<mediaitem-scroller-horizontal :items="friendsListeningTo" v-if="isSectionReady('friendsListeningTo')">
|
||||||
<mediaitem-square kind="small" v-for="item in friendsListeningTo"
|
</mediaitem-scroller-horizontal>
|
||||||
:item="item"></mediaitem-square>
|
|
||||||
</template>
|
|
||||||
<div class="spinner" v-else></div>
|
<div class="spinner" v-else></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,7 +109,9 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async seeAllHistory() {
|
async seeAllHistory() {
|
||||||
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`)
|
let hist = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {
|
||||||
|
l: this.$root.mklang
|
||||||
|
})
|
||||||
app.showCollection(hist.data, app.getLz('term.history'))
|
app.showCollection(hist.data, app.getLz('term.history'))
|
||||||
},
|
},
|
||||||
isSectionReady(section) {
|
isSectionReady(section) {
|
||||||
|
@ -143,12 +142,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playlists.length != 0) {
|
if (playlists.length != 0) {
|
||||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`).then(playlistsData => {
|
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/playlists/${playlists.toString()}`, {
|
||||||
|
l: this.$root.mklang
|
||||||
|
}).then(playlistsData => {
|
||||||
self.favorites.push(...playlistsData.data)
|
self.favorites.push(...playlistsData.data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (libraryPlaylists.length != 0) {
|
if (libraryPlaylists.length != 0) {
|
||||||
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`).then(playlistsData => {
|
this.app.mk.api.v3.music(`v1/me/library/playlists/${playlists.toString()}`, {
|
||||||
|
l: this.$root.mklang
|
||||||
|
}).then(playlistsData => {
|
||||||
self.favorites.push(...playlistsData.data)
|
self.favorites.push(...playlistsData.data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -156,7 +159,7 @@
|
||||||
async getArtistFeed() {
|
async getArtistFeed() {
|
||||||
let artists = this.followedArtists
|
let artists = this.followedArtists
|
||||||
let self = this
|
let self = this
|
||||||
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f`).then(artistData => {
|
this.app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists?ids=${artists.toString()}&views=latest-release&include[songs]=albums&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount&limit[artists:top-songs]=2&art[url]=f&l=${this.$root.mklang}`).then(artistData => {
|
||||||
artistData.data.data.forEach(item => {
|
artistData.data.data.forEach(item => {
|
||||||
if (item.views["latest-release"].data.length != 0) {
|
if (item.views["latest-release"].data.length != 0) {
|
||||||
self.artistFeed.push(item.views["latest-release"].data[0])
|
self.artistFeed.push(item.views["latest-release"].data[0])
|
||||||
|
@ -177,7 +180,7 @@
|
||||||
},
|
},
|
||||||
async getListenNowData() {
|
async getListenNowData() {
|
||||||
let self = this
|
let self = this
|
||||||
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web`).then((data) => {
|
this.app.mk.api.v3.music(`/v1/me/recommendations?timezone=${encodeURIComponent(app.formatTimezoneOffset())}&name=listen-now&with=friendsMix,library,social&art[social-profiles:url]=c&art[url]=c,f&omit[resource]=autos&relate[editorial-items]=contents&extend=editorialCard,editorialVideo&extend[albums]=artistUrl&extend[library-albums]=artistUrl,editorialVideo&extend[playlists]=artistNames,editorialArtwork,editorialVideo&extend[library-playlists]=artistNames,editorialArtwork,editorialVideo&extend[social-profiles]=topGenreNames&include[albums]=artists&include[songs]=artists&include[music-videos]=artists&fields[albums]=artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url&fields[artists]=name,url&extend[stations]=airDate,supportsAirTimeUpdates&meta[stations]=inflectionPoints&types=artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells&platform=web&l=${this.$root.mklang}`).then((data) => {
|
||||||
console.log(data.data.data[1])
|
console.log(data.data.data[1])
|
||||||
try {
|
try {
|
||||||
self.madeForYou = data.data.data.filter(section => {
|
self.madeForYou = data.data.data.filter(section => {
|
||||||
|
|
|
@ -9,12 +9,7 @@
|
||||||
<div class="col" style="padding:0;">
|
<div class="col" style="padding:0;">
|
||||||
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
<div class="search-input-container" style="width:100%;margin: 16px 0;">
|
||||||
<div class="search-input--icon"></div>
|
<div class="search-input--icon"></div>
|
||||||
<input type="search"
|
<input type="search" style="width:100%;" spellcheck="false" :placeholder="$root.getLz('term.search') + '...'" @input="searchLibraryArtists" v-model="library.artists.search" class="search-input">
|
||||||
style="width:100%;"
|
|
||||||
spellcheck="false"
|
|
||||||
:placeholder="$root.getLz('term.search') + '...'"
|
|
||||||
@input="searchLibraryArtists"
|
|
||||||
v-model="library.artists.search" class="search-input">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto flex-center">
|
<div class="col-auto flex-center">
|
||||||
|
|
|
@ -534,7 +534,7 @@
|
||||||
|
|
||||||
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(function () {
|
||||||
app.mk.setQueue({[truekind]: [id]}).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) {
|
||||||
let u = query.slice(100);
|
let u = query.slice(100);
|
||||||
|
|
|
@ -204,7 +204,7 @@
|
||||||
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
|
||||||
},
|
},
|
||||||
playEpisode(episode) {
|
playEpisode(episode) {
|
||||||
app.mk.setQueue({'episode': episode.id}).then(() => {app.mk.play()})
|
app.mk.setQueue({'episode': episode.id, parameters : {l : app.mklang}}).then(() => {app.mk.play()})
|
||||||
},
|
},
|
||||||
selectPodcast(podcast) {
|
selectPodcast(podcast) {
|
||||||
this.podcastSelected = podcast
|
this.podcastSelected = podcast
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
Vue.component('apple-account-settings', {
|
Vue.component('remote-pair', {
|
||||||
template: '#apple-account-settings',
|
template: '#remote-pair',
|
||||||
async mounted() {
|
async mounted() {
|
||||||
ipcRenderer.send('get-remote-pair-url')
|
ipcRenderer.send('get-remote-pair-url')
|
||||||
ipcRenderer.on('send-remote-pair-url', (event, url) => {
|
ipcRenderer.on('send-remote-pair-url', (event, url) => {
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
<script type="text/x-template" id="cider-search">
|
<script type="text/x-template" id="cider-search">
|
||||||
<div class="content-inner">
|
<div class="content-inner">
|
||||||
<div v-if="search != null && search != [] && search.term != ''">
|
<div v-if="search != null && search != [] && search.term != ''">
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
|
|
||||||
<template>
|
|
||||||
<h3>{{app.getLz('term.topResult')}}</h3>
|
<h3>{{app.getLz('term.topResult')}}</h3>
|
||||||
<mediaitem-square :item="getTopResult()"></mediaitem-square>
|
<mediaitem-scroller-horizontal
|
||||||
</template>
|
:items="search.results[search.results.meta.results.order[0]]['data']"></mediaitem-scroller-horizontal>
|
||||||
</div>
|
<div class="row">
|
||||||
<div v-else style="text-align: center">
|
<div v-else style="text-align: center">
|
||||||
<h3>{{app.getLz('error.noResults')}}</h3>
|
<h3>{{app.getLz('error.noResults')}}</h3>
|
||||||
<p>{{app.getLz('error.noResults.description')}}</p>
|
<p>{{app.getLz('error.noResults.description')}}</p>
|
||||||
|
@ -24,10 +21,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mediaitem-list-item__grid">
|
<div class="mediaitem-list-item__grid">
|
||||||
<div class="grid-body">
|
<listitem-horizontal :items="search.results.song.data.limit(12)">
|
||||||
<mediaitem-list-item :item="item" :index="index"
|
</listitem-horizontal>
|
||||||
v-for="(item, index) in search.results.song.data.limit(12)"></mediaitem-list-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,7 +88,7 @@
|
||||||
<mediaitem-square :kind="'385'" size="600"
|
<mediaitem-square :kind="'385'" size="600"
|
||||||
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
:item="item ? (item.attributes.kind ? item : ((item.relationships && item.relationships.contents ) ? item.relationships.contents.data[0] : item)) : []"
|
||||||
:imagesize="800"
|
:imagesize="800"
|
||||||
v-for="item in categoriesView[1].relationships.contents.data.filter(item => item.type != 'editorial-items')">
|
v-for="item of getFlattenedCategories()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -121,11 +116,24 @@
|
||||||
},
|
},
|
||||||
async getCategories() {
|
async getCategories() {
|
||||||
if (this.categoriesView != [] && this.categoriesView.length > 0) { this.categoriesReady = true; return await true; } else {
|
if (this.categoriesView != [] && this.categoriesView.length > 0) { this.categoriesReady = true; return await true; } else {
|
||||||
let response = await this.app.mk.api.v3.music(`/v1/recommendations/${this.app.mk.storefrontId}?timezone=${encodeURIComponent(this.app.formatTimezoneOffset())}&name=search-landing&platform=web&extend=editorialArtwork&art%5Burl%5D=f%2Cc&types=editorial-items%2Capple-curators%2Cactivities`);
|
let response = await this.app.mk.api.v3.music(`/v1/recommendations/${this.app.mk.storefrontId}?timezone=${encodeURIComponent(this.app.formatTimezoneOffset())}&name=search-landing&platform=web&extend=editorialArtwork&art%5Burl%5D=f%2Cc&types=editorial-items%2Capple-curators%2Cactivities&l=${this.$root.mklang}`);
|
||||||
this.categoriesView = response.data.data;
|
this.categoriesView = response.data.data;
|
||||||
|
console.log(this.categoriesView)
|
||||||
this.categoriesReady = true;
|
this.categoriesReady = true;
|
||||||
return await true;
|
return await true;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getFlattenedCategories() {
|
||||||
|
let flattened = [];
|
||||||
|
for (let i = 0; i < this.categoriesView.length; i++) {
|
||||||
|
if (this.categoriesView[i].relationships && this.categoriesView[i].relationships.contents && this.categoriesView[i].relationships.contents.data) {
|
||||||
|
for (let j = 0; j < this.categoriesView[i].relationships.contents.data.length; j++) {
|
||||||
|
if (this.categoriesView[i].relationships.contents.data[j].type != 'editorial-items')
|
||||||
|
flattened.push(this.categoriesView[i].relationships.contents.data[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flattened;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,8 +5,5 @@
|
||||||
{{ $store.state.test }}
|
{{ $store.state.test }}
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
<button class="md-btn">Cider Button</button>
|
<button class="md-btn">Cider Button</button>
|
||||||
<div style="position: relative;width: 300px;height: 300px;">
|
|
||||||
<artwork-material url="https://is3-ssl.mzstatic.com/image/thumb/Music126/v4/13/41/13/1341133b-560f-1aee-461f-c4b32ec049b4/cover.jpg/{w}x{h}bb.jpg"></artwork-material>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 17 KiB |
|
@ -13,6 +13,7 @@ var app = new Vue({
|
||||||
player: {
|
player: {
|
||||||
currentMediaItem: {},
|
currentMediaItem: {},
|
||||||
songActions: false,
|
songActions: false,
|
||||||
|
maxVolume: 1,
|
||||||
lyrics: {},
|
lyrics: {},
|
||||||
lyricsMediaItem: {},
|
lyricsMediaItem: {},
|
||||||
lyricsDebug: {
|
lyricsDebug: {
|
||||||
|
@ -161,6 +162,11 @@ var app = new Vue({
|
||||||
volume: volume
|
volume: volume
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
getVolumeMax() {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
action: "volumeMax",
|
||||||
|
}));
|
||||||
|
},
|
||||||
getQueue() {
|
getQueue() {
|
||||||
socket.send(JSON.stringify({
|
socket.send(JSON.stringify({
|
||||||
action: "get-queue"
|
action: "get-queue"
|
||||||
|
@ -570,6 +576,9 @@ var app = new Vue({
|
||||||
self.updatePlaybackState(response.data)
|
self.updatePlaybackState(response.data)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "maxVolume":
|
||||||
|
this.player.maxVolume = response.data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// console.log(e.data);
|
// console.log(e.data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@
|
||||||
<div class="player-volume-glyph decrease"></div>
|
<div class="player-volume-glyph decrease"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<input type="range" class="web-slider volume-slider" max="1" min="0" step="0.01"
|
<input type="range" class="web-slider volume-slider" :max="player.maxVolume" min="0" step="0.01" :pseudo-value="getVolumeMax()"
|
||||||
@input="setVolume($event.target.value)" :value="player.currentMediaItem.volume">
|
@input="setVolume($event.target.value)" :value="player.currentMediaItem.volume">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
|
|