* Update ru_RU.json

keeping russian lang actual

* ok

* Add gradient to lyric-footer

* *Commit en español Ñ (#1304)

* i hate my life (#1307)

* world is now a better place

* meltdown avoided

* meltdown avoided

* stylize new listen now childs

* full scale artwork, finally

* dynamic width for search categories

* hd all album work

* Update afterPack.js

* force hq quality

* oops

* attempt to fix

* misc cleanup

* why what

* what was i thinking

* fix duplicated text in listen now childs

* Paginate/infinite scroll for  albums, playlists (#1234)

* Infinite scroll, pagination to album, playlists

* move pagination below tracks

* Make page size configurable

* remove renderer

* Mitigate songs / album slow app issue.

* add ratings, library change to web remote (#1285)

* Add compact artist header option (#1308)

* Support compact artist header (optional)

* Add required term

* pain e19 still bugged

* improve pagination styling

* el16 fix

* up 1.5.2

* Disable Fullscreen view when artist/album name is clicked. (#1315)

* Disable Fullscreen view when artist/album name is clicked.

idk why this change didn't exist

* Seperate dash from album name

* Replace `$root.showSearch()` with `app.appRoute('search')`

`$root.showSearch()` prevents going back to previous page from sidebar.

* Fix Anim (#1316)

* make tracks tab active (#1318)

* welp that wasn't it.

* Thnks (#1319)

* Thnks

* i need sleep

* Update cider-playlist.ejs

* remove v-ripple

* attempt to fix flatpak

* Update config.yml

* minimize categories names

* fix versioning

* fix versioning v2

* version fix v3 - final

* fix categories name for other storefronts

* ident unparsed title

* center fullscreen

* fix share

* Add protocol for playpause and nextitem (#1329)

* Moved to minimize hide window instead of close

* Moved state saving to before quit

* build test

* fix ci

* sudo

* ci

* use old branch fn

* d

* revert

* Exposed songid in attributes, reimplemented lastfm primary artist scrobbling, cleaned up mkinterop

* Moved it back

* im over this

* attempt airts

* use new airtunes branch

* *eye roll*

* Moved time conversion to built-in MK function

* Moved to Electron Notifications

* Swapped to array index

* keeping this here until for now

* debuggin

* run ci

* allow noti button on macs

* No image for now

* revert space

* Latest releases -> Latest Release

* Artwork caching (sorta)

* holy balls optimization

* save sentry from this

Co-authored-by: h0ckerman <35598335+h0ckerman@users.noreply.github.com>
Co-authored-by: vapormusic <vietanhfat@gmail.com>
Co-authored-by: Monochromish <chillygamer7@gmail.com>
Co-authored-by: Gabriel Davila <56521591+mefsaal@users.noreply.github.com>
Co-authored-by: Core <64542347+coredev-uk@users.noreply.github.com>
Co-authored-by: Maikiwi <stella@mai.kiwi>
Co-authored-by: yazninja <yazlesean@gmail.com>
Co-authored-by: booploops <49113086+booploops@users.noreply.github.com>
Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com>
Co-authored-by: Pedro Galhardo <pgalhardo@icloud.com>
Co-authored-by: Monochromish <79590499+Monochromish@users.noreply.github.com>
Co-authored-by: Core <core@c0r3.uk>
This commit is contained in:
cryptofyre 2022-07-31 21:28:51 -05:00 committed by GitHub
parent a99dddf2b6
commit 5ed045aad1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 298 additions and 183 deletions

View file

@ -15,6 +15,11 @@ jobs:
executor: cider-ci
steps:
- checkout
- run:
name: Install buildtools
command: |
sudo apt-get update
sudo apt-get install -y autoconf automake g++ libtool || true
- run:
name: Update Version Number of App
command: sudo chmod +x resources/version.sh && ./resources/version.sh || true

View file

@ -91,6 +91,7 @@ jobs:
run: |
rm cider-yarn.lock || true
xcodebuild -version
brew install autoconf automake libtool
yarn install
cp resources/verror-types node_modules/@types/verror/index.d.ts
cp resources/macPackager.js node_modules/app-builder-lib/out/macPackager.js

View file

@ -227,7 +227,10 @@
"darkModeSupport": true,
"target": [
"dmg"
]
],
"extendInfo": {
"NSUserNotificationAlertStyle": "alert"
}
}
}
}

View file

@ -1,7 +1,8 @@
#!/bin/bash
LATEST_SHA=$(curl -s https://api.github.com/repos/ciderapp/Cider/branches/stable | grep sha | cut -d '"' -f 4 | sed 's/v//' | xargs)
COMMITSINCESTABLE=$(git rev-list $LATEST_SHA..HEAD --count)
LATEST_SHA=$(curl -s https://api.github.com/repos/ciderapp/Cider/branches/stable | grep '"sha"' | head -1 | cut -d '"' -f 4)
SHA_DATE=$(git show -s --format=%ci $LATEST_SHA)
COMMITSINCESTABLE=$(git rev-list $LATEST_SHA..HEAD --count --since="$SHA_DATE")
CURRENT_VERSION=$(node -p -e "require('./package.json').version")
if [[ $CIRCLE_BRANCH == "main" && $COMMITSINCESTABLE -gt 0 ]]; then
NEW_VERSION="${CURRENT_VERSION}-beta.${COMMITSINCESTABLE}"

View file

@ -108,7 +108,7 @@
"term.showMore": "Show more",
"term.showLess": "Show less",
"term.topSongs": "Top Songs",
"term.latestReleases": "Latest Releases",
"term.latestReleases": "Latest Release",
"term.time.added": "Added",
"term.time.released": "Released",
"term.time.updated": "Updated",

View file

@ -108,7 +108,7 @@
"term.showMore": "Show more",
"term.showLess": "Show less",
"term.topSongs": "Top Songs",
"term.latestReleases": "Latest Releases",
"term.latestReleases": "Latest Release",
"term.time.added": "Added",
"term.time.released": "Released",
"term.time.updated": "Updated",

View file

@ -168,6 +168,14 @@ export class AppEvents {
utils.getWindow().webContents.executeJavaScript(`ipcRenderer.send('lastfm:auth', "${authURI.split('lastfm?token=')[1]}")`).catch(console.error)
}
}
else if (arg.includes('playpause')) {
//language=JS
utils.getWindow().webContents.executeJavaScript('MusicKitInterop.playPause()')
}
else if (arg.includes('nextitem')) {
//language=JS
utils.getWindow().webContents.executeJavaScript('app.mk.skipToNextItem()')
}
// Play
else if (arg.includes('/play/')) { //Steer away from protocol:// specific conditionals
const playParam = arg.split('/play/')[1]

View file

@ -1183,11 +1183,6 @@ export class BrowserWindow {
app.quit();
})
app.on('before-quit', () => {
})
ipcMain.on('play', (_event, type, id) => {
BrowserWindow.win.webContents.executeJavaScript(`
MusicKit.getInstance().setQueue({ ${type}: '${id}', parameters : {l : app.mklang}}).then(function(queue) {
@ -1442,70 +1437,63 @@ export class BrowserWindow {
FULL_SCREEN: 3,
};
let wndState = WND_STATE.NORMAL;
const win = BrowserWindow.win;
let isQuitting = false;
BrowserWindow.win.on("resize", (_: any) => {
const isMaximized = BrowserWindow.win.isMaximized();
const isMinimized = BrowserWindow.win.isMinimized();
const isFullScreen = BrowserWindow.win.isFullScreen();
win.on("resize", (_: any) => {
const isMaximized = win.isMaximized();
const isMinimized = win.isMinimized();
const isFullScreen = win.isFullScreen();
const state = wndState;
if (isMinimized && state !== WND_STATE.MINIMIZED) {
wndState = WND_STATE.MINIMIZED;
BrowserWindow.win.webContents.send('window-state-changed', 'minimized');
win.webContents.send('window-state-changed', 'minimized');
} else if (isFullScreen && state !== WND_STATE.FULL_SCREEN) {
wndState = WND_STATE.FULL_SCREEN;
BrowserWindow.win.webContents.send('window-state-changed', 'fullscreen')
win.webContents.send('window-state-changed', 'fullscreen')
} else if (isMaximized && state !== WND_STATE.MAXIMIZED) {
wndState = WND_STATE.MAXIMIZED;
BrowserWindow.win.webContents.send('window-state-changed', 'maximized')
BrowserWindow.win.webContents.executeJavaScript(`app.chrome.maximized = true`);
win.webContents.send('window-state-changed', 'maximized')
win.webContents.executeJavaScript(`app.chrome.maximized = true`);
} else if (state !== WND_STATE.NORMAL) {
wndState = WND_STATE.NORMAL;
BrowserWindow.win.webContents.send('window-state-changed', 'normal')
BrowserWindow.win.webContents.executeJavaScript(
win.webContents.send('window-state-changed', 'normal')
win.webContents.executeJavaScript(
`app.chrome.maximized = false`
);
}
});
win.on("close", (e: any) => {
if ((process.platform === "darwin" || utils.getStoreValue("general.close_button_hide")) && !isQuitting) {
e.preventDefault()
win.hide()
}
})
let isQuiting = false
BrowserWindow.win.on("close", (event: Event) => {
if ((utils.getStoreValue('general.close_button_hide') || process.platform === "darwin") && !isQuiting) {
event.preventDefault();
BrowserWindow.win.hide();
} else {
BrowserWindow.win.webContents.executeJavaScript(`
win.on("closed", (_: any) => {
win.webContents.executeJavaScript(`
window.localStorage.setItem("currentTrack", JSON.stringify(app.mk.nowPlayingItem));
window.localStorage.setItem("currentTime", JSON.stringify(app.mk.currentPlaybackTime));
window.localStorage.setItem("currentQueue", JSON.stringify(app.mk.queue._unplayedQueueItems));
ipcRenderer.send('stopGCast','');`)
BrowserWindow.win.destroy();
}
})
app.on('before-quit', () => {
isQuiting = true
isQuitting = true;
});
app.on('activate', function () {
BrowserWindow.win.show()
BrowserWindow.win.focus()
win.show()
});
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
BrowserWindow.win.on("closed", () => {
BrowserWindow.win = null;
});
// Set window Handler
BrowserWindow.win.webContents.setWindowOpenHandler((x: any) => {
if (x.url.includes("apple") || x.url.includes("localhost")) {

View file

@ -65,6 +65,7 @@ export class Store {
],
"albums": [
"CommandOrControl",
process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift" : "Alt"),
"A"
],
"artists": [
@ -134,6 +135,7 @@ export class Store {
"scrobble_after": 50,
"filter_loop": false,
"filter_types": {},
"remove_featured": false,
"secrets": {
"username": "",
"key": ""

View file

@ -90,7 +90,8 @@ export class utils {
if (language !== "en_US" && fs.existsSync(path.join(this.paths.i18nPath, `${language}.json`))) {
i18n = Object.assign(i18n, JSON.parse(fs.readFileSync(path.join(this.paths.i18nPath, `${language}.json`), "utf8")));
} else if (!fs.existsSync(path.join(this.paths.i18nPath, `${language}.json`))) {
}
/* else if (!fs.existsSync(path.join(this.paths.i18nPath, `${language}.json`))) {
fetch(`https://raw.githubusercontent.com/ciderapp/Cider/main/src/i18n/${language}.json`)
.then(res => res.json())
.then(res => {
@ -101,7 +102,8 @@ export class utils {
i18n = Object.assign(i18n, JSON.parse(fs.readFileSync(path.join(this.paths.i18nPath, `en_US.json`), "utf8")));
}
})
}
} */
if (key) {
return i18n[key]
} else {

View file

@ -131,7 +131,7 @@ export default class lastfm {
if (!attributes.lfmAlbum) {
this._lfm.album.getInfo({
"artist": attributes.artistName,
"artist": attributes.primaryArtist,
"album": attributes.albumName
}, (err: any, data: any) => {
if (err) {
@ -144,7 +144,7 @@ export default class lastfm {
}
})
} else {
this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => {
this._lfm.track.getCorrection(attributes.primaryArtist, attributes.name, (err: any, data: any) => {
if (err) {
console.error(`[${lastfm.name}] [track.getCorrection] Error: ${typeof err === "string" ? err : err.message}`)
return {};

View file

@ -0,0 +1,118 @@
import fetch from "electron-fetch";
import {nativeImage, Notification} from "electron";
import NativeImage = Electron.NativeImage;
export default class playbackNotifications {
/**
* Base Plugin Details (Eventually implemented into a GUI in settings)
*/
public name: string = 'Playback Notifications';
public description: string = 'Creates notifications on playback.';
public version: string = '1.0.0';
public author: string = 'Core';
public contributors: string[] = ['Core', 'Monochromish'];
private _utils: any;
private _notification: Notification | undefined;
private _artworkImage: { [key: string]: NativeImage } = {};
private _artworkNums: Array<string> = [];
/**
* Creates playback notification
* @param a: Music Attributes
*/
createNotification(a: any): void {
if (this._notification) {
this._notification.close();
}
this._notification = new Notification({
title: a.name,
body: `${a.artistName}${a.albumName}`,
silent: true,
icon: this._artworkImage[a.artwork.url],
urgency: 'low',
actions: [
{
'type': 'button',
'text': 'Play/Pause'
},
{
'type': 'button',
'text': 'Next'
}
],
toastXml: `
<toast>
<visual>
<binding template="ToastText02">
<text id="1">${a?.name.replace(/&/g, '&amp;')}</text>
<text id="2">${a?.artistName.replace(/&/g, '&amp;')} ${a?.albumName.replace(/&/g, '&amp;')}</text>
</binding>
</visual>
<actions>
<action content="Play/Pause" activationType="protocol" arguments="cider://playpause/"/>
<action content="Next" activationType="protocol" arguments="cider://nextitem/"/>
</actions>
</toast>`
});
// image implementation in windows toasts
//<image id="1" src="path to image" alt="img"/>
this._notification.on('click', (_: any) => {
this._utils.getWindow().show()
this._utils.getWindow().focus()
})
this._notification.on('close', (_: any) => {
this._notification = undefined;
})
this._notification.on('action', (event: any, action: any) => {
if (action === 0) {
this._utils.playback.playPause()
} else if (action === 1) {
this._utils.playback.next()
}
})
this._notification.show();
}
/*******************************************************************************************
* Public Methods
* ****************************************************************************************/
/**
* Runs on plugin load (Currently run on application start)
*/
constructor(utils: any) {
this._utils = utils;
console.debug(`[Plugin][${this.name}] Loading Complete.`);
utils.getIPCMain().on('playbackNotifications:create', (event: any, a: any) => {
a.artwork.url = a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb');
if (this._artworkNums.length > 20) {
delete this._artworkImage[this._artworkNums[0]];
this._artworkNums.shift();
}
if (this._artworkImage[a.artwork.url]) {
this.createNotification(a);
} else {
fetch(a.artwork.url).then(async blob => {
this._artworkImage[a.artwork.url] = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer()));
this._artworkNums[this._artworkNums.length] = a.artwork.url;
this.createNotification(a);
});
}
})
}
}

View file

@ -88,14 +88,16 @@ export default class RAOP {
`;
private ondeviceup(name: any, host: any, port: any, addresses: any, text: any) {
if (this.castDevices.findIndex((item: any) => item.name == host.replace(".local","") && item.port == port && item.addresses == addresses) === -1) {
private ondeviceup(name: any, host: any, port: any, addresses: any, text: any, airplay2: any = null) {
console.log(this.castDevices.findIndex((item: any) => {return (item.name == host.replace(".local","") && item.port == port )}))
if (this.castDevices.findIndex((item: any) => {return (item.name == host.replace(".local","") && item.port == port )}) == -1) {
this.castDevices.push({
name: host.replace(".local",""),
host: addresses ? addresses[0] : '',
port: port,
addresses: addresses,
txt: text
txt: text,
airplay2: airplay2
});
if (this.devices.indexOf(host) === -1) {
this.devices.push(host);
@ -147,7 +149,7 @@ export default class RAOP {
browser.on('ready', browser.discover);
browser.on('update', (service: any) => {
if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) {
if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp'))) {
// console.log(service.txt)
this._win.webContents.executeJavaScript(`console.log(
"${service.name} ${service.host}:${service.port} ${service.addresses}"
@ -156,6 +158,19 @@ export default class RAOP {
}
});
const browser2 = this.mdns.createBrowser(this.mdns.tcp('airplay'));
browser2.on('ready', browser2.discover);
browser2.on('update', (service: any) => {
if (service.addresses && service.fullname && (service.fullname.includes('_airplay._tcp'))) {
// console.log(service.txt)
this._win.webContents.executeJavaScript(`console.log(
"${service.name} ${service.host}:${service.port} ${service.addresses}"
)`);
this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt, true);
}
});
// const browser2 = this.mdns.createBrowser(this.mdns.tcp('airplay'));
// browser2.on('ready', browser2.discover);
@ -173,7 +188,7 @@ export default class RAOP {
electron.ipcMain.on("performAirplayPCM", (event, ipv4, ipport, sepassword, title, artist, album, artworkURL,txt) => {
electron.ipcMain.on("performAirplayPCM", (event, ipv4, ipport, sepassword, title, artist, album, artworkURL,txt,airplay2dv) => {
if (ipv4 != this.ipairplay || ipport != this.portairplay) {
if (this.airtunes == null) { this.airtunes = new this.u()}
@ -183,7 +198,9 @@ export default class RAOP {
port: ipport,
volume: 50,
password: sepassword,
txt: txt
txt: txt,
airplay2: airplay2dv,
debug: true
});
// console.log('lol',txt)
this.device.on('status', (status: any) => {

View file

@ -6,6 +6,7 @@ let cache = {playParams: {id: 0}, status: null, remainingTime: 0},
const MusicKitInterop = {
init: function () {
/* MusicKit.Events.playbackStateDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.playbackStateDidChange, () => {
const attributes = MusicKitInterop.getAttributes()
if (MusicKitInterop.filterTrack(attributes, true, false)) {
@ -14,19 +15,28 @@ const MusicKitInterop = {
}
});
/** wsapi */
MusicKit.getInstance().addEventListener(MusicKit.Events.playbackProgressDidChange, () => {
ipcRenderer.send('wsapi-updatePlaybackState', MusicKitInterop.getAttributes());
/* MusicKit.Events.playbackProgressDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.playbackProgressDidChange, async () => {
const attributes = MusicKitInterop.getAttributes()
// wsapi call
ipcRenderer.send('wsapi-updatePlaybackState', attributes);
// lastfm call
if (app.mk.currentPlaybackProgress === (app.cfg.connectivity.lastfm.scrobble_after / 100)) {
attributes.primaryArtist = (app.cfg.connectivity.lastfm.enabled && app.cfg.connectivity.lastfm.remove_featured) ? await this.fetchPrimaryArtist(attributes.artistName) : attributes.artistName;
ipcRenderer.send('lastfm:scrobbleTrack', attributes);
}
});
/** wsapi */
/* MusicKit.Events.playbackTimeDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.playbackTimeDidChange, () => {
ipcRenderer.send('mpris:playbackTimeDidChange', (MusicKit.getInstance()?.currentPlaybackTime * 1000 * 1000) ?? 0);
})
});
/* MusicKit.Events.nowPlayingItemDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, async () => {
console.debug('[cider:preload] nowPlayingItemDidChange')
const attributes = MusicKitInterop.getAttributes()
attributes.primaryArtist = (app.cfg.connectivity.lastfm.enabled && app.cfg.connectivity.lastfm.remove_featured) ? await this.fetchPrimaryArtist(attributes.artistName) : attributes.artistName;
if (MusicKitInterop.filterTrack(attributes, false, true)) {
global.ipcRenderer.send('nowPlayingItemDidChange', attributes);
@ -34,24 +44,32 @@ const MusicKitInterop = {
global.ipcRenderer.send('lastfm:nowPlayingChange', attributes);
}
if (app.cfg.general.playbackNotifications && !document.hasFocus() && attributes.artistName && attributes.artwork && attributes.name) {
global.ipcRenderer.send('playbackNotifications:create', attributes);
}
if (MusicKit.getInstance().nowPlayingItem) {
await this.sleep(750);
MusicKit.getInstance().playbackRate = app.cfg.audio.playbackRate;
}
});
/* MusicKit.Events.authorizationStatusDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.authorizationStatusDidChange, () => {
global.ipcRenderer.send('authorizationStatusDidChange', MusicKit.getInstance().authorizationStatus)
});
/* MusicKit.Events.mediaPlaybackError */
MusicKit.getInstance().addEventListener(MusicKit.Events.mediaPlaybackError, (e) => {
console.warn(`[cider:preload] mediaPlaybackError] ${e}`);
});
/* MusicKit.Events.shuffleModeDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.shuffleModeDidChange, () => {
global.ipcRenderer.send('shuffleModeDidChange', MusicKit.getInstance().shuffleMode)
});
/* MusicKit.Events.repeatModeDidChange */
MusicKit.getInstance().addEventListener(MusicKit.Events.repeatModeDidChange, () => {
global.ipcRenderer.send('repeatModeDidChange', MusicKit.getInstance().repeatMode)
});
@ -63,6 +81,15 @@ const MusicKitInterop = {
});
},
async fetchPrimaryArtist(artist) {
if (app.mk.nowPlayingItem?.relationships?.artists) {
const artist = await app.mk.api.artist(app.mk.nowPlayingItem.relationships.artists.data[0].id)
return artist.attributes.name
} else {
return artist
}
},
getAttributes: function () {
const mk = MusicKit.getInstance()
const nowPlayingItem = mk.nowPlayingItem;
@ -71,6 +98,7 @@ const MusicKitInterop = {
const currentPlaybackProgress = mk.currentPlaybackProgress;
const attributes = (nowPlayingItem != null ? nowPlayingItem.attributes : {});
attributes.songId = attributes.songId ?? attributes.playParams?.catalogId ?? attributes.playParams?.id
attributes.status = isPlayingExport ?? null;
attributes.name = attributes?.name ?? 'no-title-found';
attributes.artwork = attributes?.artwork ?? {url: ''};

View file

@ -480,6 +480,7 @@
display: inline-flex;
width: 100%;
justify-content: center;
align-items: center;
}
}

View file

@ -33,11 +33,14 @@ if (app.cfg.advanced.disableLogging === true) {
// Mount Vue to #app
app.$mount("#app")
// Init CiderAudio
if (app.cfg.advanced.AudioContext === true) {
CiderAudio.init()
// Init CiderAudio and force audiocontext
if (app.cfg.advanced.AudioContext != true) {
app.cfg.advanced.AudioContext = true;
window.location.reload();
}
CiderAudio.init()
// Import gamepad support
app.simulateGamepad = simulateGamepad
app.spawnMica = spawnMica

View file

@ -949,12 +949,6 @@ const app = new Vue({
}
});
this.mk.addEventListener(MusicKit.Events.playbackProgressDidChange, () => {
if (self.mk.currentPlaybackProgress === (app.cfg.connectivity.lastfm.scrobble_after / 100)) {
ipcRenderer.send('lastfm:scrobbleTrack', MusicKitInterop.getAttributes());
}
})
this.mk.addEventListener(MusicKit.Events.playbackStateDidChange, (event) => {
ipcRenderer.send('wsapi-updatePlaybackState', wsapi.getAttributes());
document.body.setAttribute("playback-state", event.state == 2 ? "playing" : "paused")
@ -1013,8 +1007,8 @@ const app = new Vue({
try {localStorage.setItem("playingBitrate", app.mk.nowPlayingItem.flavor)}
catch(e) {}
}
if (!app.cfg.audio.normalization && app.cfg.advanced.AudioContext === false) { CiderAudio.hierarchical_loading(); }
if (app.cfg.audio.normalization === false) { CiderAudio.hierarchical_loading(); } // Just Reload for Adaptive CAP if norm is off
else {
// get unencrypted audio previews to get SoundCheck's normalization tag
try {
@ -1080,17 +1074,6 @@ const app = new Vue({
app.getNowPlayingArtworkBG(32);
app.loadLyrics();
// Playback Notifications
if (this.cfg.general.playbackNotifications && !document.hasFocus() && a.artistName && a.artwork && a.name) {
if (this.notification) {
this.notification.close()
}
this.notification = new Notification(a.name, {
body: `${a.artistName}${a.albumName}`,
icon: a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb'),
silent: true,
});
}
setTimeout(() => {
let i = (document.querySelector('#apple-music-player')?.src ?? "")
if (i.endsWith(".m3u8") || i.endsWith(".m3u")) {
@ -1887,27 +1870,7 @@ const app = new Vue({
return dDisplay + (dDisplay && hDisplay ? ", " : "") + hDisplay + (hDisplay && mDisplay ? ", " : "") + mDisplay;
} else {
let returnTime = datetime.toISOString().substring(11, 19);
const timeGates = {
600: 15, // 10 Minutes
3600: 14, // Hour
36000: 12, // 10 Hours
}
for (let key in timeGates) {
if (seconds < key) {
returnTime = datetime.toISOString().substring(timeGates[key], 19)
break
}
}
// Add the days on the front
if (seconds >= 86400) {
returnTime = parseInt(datetime.toISOString().substring(8, 10)) - 1 + ":" + returnTime
}
return returnTime
return MusicKit.formatMediaTime(seconds);
}
},
hashCode(str) {
@ -4391,7 +4354,7 @@ const app = new Vue({
"id": "equalizer",
"icon": "../views/svg/speaker.svg",
"name": app.getLz('term.equalizer'),
"hidden": true,
"hidden": false,
"action": function () {
app.modals.equalizer = true
app.modals.audioSettings = false
@ -4401,7 +4364,7 @@ const app = new Vue({
"id": "audioLab",
"icon": "../views/svg/speaker.svg",
"name": app.getLz('settings.option.audio.audioLab'),
"hidden": true,
"hidden": false,
"action": function () {
app.openSettingsPage('audiolabs')
}
@ -4409,10 +4372,12 @@ const app = new Vue({
]
}
}
/*
if (this.cfg.advanced.AudioContext) {
menus.normal.items.find(i => i.id === 'audioLab').hidden = false
menus.normal.items.find(i => i.id === 'equalizer').hidden = false
}
*/
if (this.contextExt) {
if (this.contextExt.normal) {
menus.normal.items = menus.normal.items.concat(this.contextExt.normal)

View file

@ -65,7 +65,7 @@
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.castMenu = true :(cfg.advanced.AudioContext = true, modals.castMenu = true)"
@click="modals.castMenu = true"
>
<span class="usermenu-item-icon">
<%- include("../svg/cast.svg") %>
@ -76,7 +76,7 @@
</button>
<button
class="usermenu-item"
@click="cfg.advanced.AudioContext ? modals.audioSettings = true : (cfg.advanced.AudioContext = true, modals.audioSettings = true)"
@click="modals.audioSettings = true"
>
<span class="usermenu-item-icon">
<%- include("../svg/headphones.svg") %>

View file

@ -152,7 +152,7 @@
<button class="playback-button--small cast"
:title="$root.getLz('term.cast')"
v-b-tooltip.hover
@click="cfg.advanced.AudioContext ? modals.castMenu = true : (cfg.advanced.AudioContext = true, modals.castMenu = true)"></button>
@click="modals.castMenu = true"></button>
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small queue" :class="{'active': drawer.panel == 'queue'}"

View file

@ -231,7 +231,7 @@
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small cast" :title="$root.getLz('term.cast')"
@click="cfg.advanced.AudioContext ? modals.castMenu = true : (cfg.advanced.AudioContext = true, modals.castMenu = true)"
@click="modals.castMenu = true"
v-b-tooltip.hover></button>
</div>
<div class="app-chrome-item generic">

View file

@ -3,7 +3,7 @@
<div class="modal-window airplay-modal">
<div class="modal-header">
<div class="modal-title">{{'Enter password'}}</div>
<button class="close-btn" @click="close()" :aria-label="app.getLz('action.close')"></button>
<button class="close-btn" @click="close()" :aria-label="this.$root.getLz('action.close')"></button>
</div>
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
<input type="text" v-model="passcode"/>

View file

@ -116,7 +116,7 @@
},
setAirPlayCast(device) {
this.activeCasts.push(device);
ipcRenderer.send("performAirplayPCM",device.host,device.port,null,"","","","",device.txt)
ipcRenderer.send("performAirplayPCM",device.host,device.port,null,"","","","",device.txt,device.airplay2)
},
stopCasting() {
CiderAudio.stopAudio();

View file

@ -452,10 +452,16 @@
{
"icon": "./assets/feather/share.svg",
"name": app.getLz('action.share'),
"action": function () {
if (!self.item.attributes.url && self.item.relationships) {
if (self.item.relationships.catalog) {
app.mkapi(self.item.attributes.playParams?.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
"action": async function () {
let item = self.item
if (!item.attributes.url) {
if (item.type.includes("library")) {
let result = (await app.mk.api.v3.music(`/v1/me/library/${item.type.replace("library-", '')}/${item.id}/catalog`)).data.data[0]
if(result.attributes.url) {
self.app.copyToClipboard(result.attributes.url)
}else{
notyf.error("Failed to get share URL")
}
}
} else {
self.app.copyToClipboard(self.item.attributes.url)
@ -465,10 +471,16 @@
{
"icon": "./assets/feather/share.svg",
"name": `${app.getLz('action.share')} (song.link)`,
"action": function () {
if (!self.item.attributes.url && self.item.relationships) {
if (self.item.relationships.catalog) {
app.mkapi(self.item.attributes.playParams?.kind, false, self.item.relationships.catalog.data[0].id).then(u => { self.app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) })
"action": async function () {
let item = self.item
if (!item.attributes.url) {
if (item.type.includes("library")) {
let result = (await app.mk.api.v3.music(`/v1/me/library/${item.type.replace("library-", '')}/${item.id}/catalog`)).data.data[0]
if(result.attributes.url) {
self.app.copyToClipboard(result.attributes.url)
}else{
notyf.error("Failed to get share URL")
}
}
} else {
self.app.songLinkShare(self.item.attributes.url)

View file

@ -45,7 +45,7 @@
<div class="title"
:title="item.attributes?.name ?? (item.relationships?.contents?.data[0]?.attributes?.name ?? (item.attributes?.editorialNotes?.name ?? ''))"
v-if="item.attributes.artistNames == null || kind != 'card'" @click='app.routeView(item)'>
<div class="item-navigate text-overflow-elipsis">{{ item.attributes?.name ??
<div class="item-navigate text-overflow-elipsis">{{ item.attributes?.name.replace(/&nbsp;/g, ' ').replace(/Apple Music |^Apple |/g, '') ??
(item.relationships?.contents?.data[0]?.attributes?.name ??
(item.attributes?.editorialNotes?.name ?? '')) }}
</div>

View file

@ -348,20 +348,6 @@
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality')}}
<br>
<small>{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.description')}}</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.advanced.AudioContext"
v-on:change="toggleAudioContext"
switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext">
<div class="md-option-segment">
{{$root.getLz('term.equalizer')}}
</div>
@ -371,7 +357,7 @@
</button>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext">
<div class="md-option-line">
<div class="md-option-segment" style="white-space: pre-line;">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.audioNormalization')}}
<small>{{app.cfg.audio.equalizer.vibrantBass != 0 ||
@ -391,7 +377,7 @@
</div>
</div>
<div class="md-option-line"
v-show="app.cfg.advanced.AudioContext && app.cfg.audio.normalization && app.cfg.audio.advanced">
v-show="app.cfg.audio.normalization && app.cfg.audio.advanced">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.dbspl.display')}}
<br>
@ -419,7 +405,7 @@
</div>
</div>
</b-tab>
<b-tab v-if="app.cfg.advanced.AudioContext">
<b-tab>
<template #title>
<div>
<svg-icon url="./assets/feather/zap.svg" classes="svg-md" name="settings-audiolabs"/>
@ -1062,6 +1048,17 @@
</label>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.connectivity.lastfm.enabled">
<div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.lastfmScrobble.removeFeatured')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.connectivity.lastfm.remove_featured"
switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.connectivity.lastfm.enabled">
<div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.lastfmScrobble.filterTypes')}}
@ -1462,21 +1459,6 @@
removeExperiment(flag) {
app.cfg.advanced.experiments.splice(app.cfg.advanced.experiments.indexOf(flag), 1);
},
toggleAudioContext: function () {
if (app.cfg.advanced.AudioContext === true) {
if (navigator.hardwareConcurrency < 6) {
app.confirm(app.getLz("settings.warn.audio.enableAdvancedFunctionality.lowcores"), function (result) {
if (result) {
window.location.reload();
}
})
} else {
window.location.reload()
}
} else {
window.location.reload()
}
},
toggleNormalization: function () {
if (app.cfg.audio.normalization) {
CiderAudio.normalizerOn()

View file

@ -6,15 +6,7 @@
<b-jumbotron :header="$root.getLz('settings.option.audio.audioLab')"
lead="Designed by Cider Acoustic Technologies in California"></b-jumbotron>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === false">
<div class="md-option-segment">
{{$root.getLz('settings.warn.audioLab.withoutAF')}}
</div>
<button class="md-btn" style="margin-top: 5px;" onclick="app.appRoute('settings')">
{{$root.getLz('term.settings')}}
</button>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')}}
<br>
@ -44,7 +36,7 @@
</select>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
Cider Opportunistic Correction System
<br>
@ -59,7 +51,7 @@
</select>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [1]
<br>
@ -84,7 +76,7 @@
</select>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}} [2]
<br>
@ -109,7 +101,7 @@
</select>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization')}}
<br>
@ -139,7 +131,7 @@
<div class="md-option-header">
<span>{{$root.getLz('settings.header.unfinished')}}</span>
</div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext === true">
<div class="md-option-line">
<div class="md-option-segment">
Cider Origami™ Vocal Enhancer/Remasterer
<br>

View file

@ -98,19 +98,6 @@
<div class="md-option-container">
<div class="settings-option-body">
<div class="md-option-line">
<div class="md-option-segment">
{{getLz('settings.option.audio.enableAdvancedFunctionality')}}
<br>
<small>{{getLz('settings.option.audio.enableAdvancedFunctionality.description')}}</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="$root.cfg.advanced.AudioContext"
switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="$root.cfg.advanced.AudioContext === true">
<div class="md-option-segment">
{{$root.getLz('settings.option.audio.enableAdvancedFunctionality.ciderPPE')}}
<br>