diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5a6ef76e..fb495fd0 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -136,11 +136,11 @@ jobs:
if [[ "${APP_VERSION}" = *"beta"* ]]; then
echo $'**Beta Release**\nA full changelog is unavailable, but you can view the branch comparison [here](https://github.com/ciderapp/cider/compare/stable...main).\nThese builds are considered bleeding edge, expect bugs and please do not use this as a representation of the fu ll app.\nOur full support disclaimer can be found [here](https://docs.cider.sh/support/disclaimer#support-nightly-beta-releases).' > release-notes.md
gh release create "v${APP_VERSION}" --prerelease --title "Cider Version ${APP_VERSION} (${CIRCLE_BRANCH})" --notes-file release-notes.md -R ciderapp/cider-releases ~/Cider/dist/artifacts/*.deb ~/Cider/dist/artifacts/*.AppImage ~/Cider/dist/artifacts/*.snap ~/Cider/dist/artifacts/*.exe ~/Cider/dist/artifacts/*.yml ~/Cider/dist/artifacts/*.blockmap
- curl http://129.146.42.180/api/v1/github/sync/main
+ curl -s http://129.146.42.180/api/v1/github/sync/main
else
echo $'**Stable Release**\nA full changelog is unavailable, but you can view the branch comparison [here](https://github.com/ciderapp/cider/compare/stable...main).\nThese are the most stable builds we can provide. If you experience any issues, please report them [here](https://github.com/ciderapp/cider/issues/new).\nOur full support disclaimer can be found [here](https://docs.cider.sh/support/disclaimer#support-releases).' > release-notes.md
gh release create "v${APP_VERSION}" --title "Cider Version ${APP_VERSION} (${CIRCLE_BRANCH})" --notes-file release-notes.md -R ciderapp/cider-releases ~/Cider/dist/artifacts/*.deb ~/Cider/dist/artifacts/*.AppImage ~/Cider/dist/artifacts/*.snap ~/Cider/dist/artifacts/*.exe ~/Cider/dist/artifacts/*.yml ~/Cider/dist/artifacts/*.blockmap
- curl http://129.146.42.180/api/v1/github/sync/stable
+ curl -s http://129.146.42.180/api/v1/github/sync/stable
fi;
# Orchestrate our job run sequence
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 00c9fea1..5009beff 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -10,7 +10,7 @@ contact_links:
url: https://discord.com/invite/AppleMusic
about: For quick support, make a ticket or ask for community support here.
- name: Cider Documentation
- url: https://docs.cider.sh/support/troubleshooting
+ url: https://docs.cider.sh/support/faqs
about: In most cases, these troubleshooting tips can resolve basic issues. Try them out before opening an issue.
- name: GitHub Issues
url: https://github.com/ciderapp/Cider/issues
diff --git a/.github/workflows/cider-chores.yml b/.github/workflows/cider-chores.yml
index dfb3eb59..48136a22 100644
--- a/.github/workflows/cider-chores.yml
+++ b/.github/workflows/cider-chores.yml
@@ -69,7 +69,7 @@ jobs:
commit_message: "chore: Prettified Code\n [ci skip]"
commit_user_name: "cider-chore[bot]"
commit_user_email: "cider-chore[bot]@users.noreply.github.com"
-
+
update-i18n-source:
runs-on: ubuntu-latest
@@ -93,7 +93,8 @@ jobs:
commit_message: "chore: Updated i18n Source\n [ci skip]"
commit_user_name: "cider-chore[bot]"
commit_user_email: "cider-chore[bot]@users.noreply.github.com"
-
+
+
synchronize-with-crowdin:
runs-on: ubuntu-latest
if: ${{ false }} # disable for now
diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json
index 9163dd1b..38267fe3 100644
--- a/src/i18n/en_US.json
+++ b/src/i18n/en_US.json
@@ -219,6 +219,7 @@
"action.favorite": "Favorite",
"action.removeFavorite": "Remove Favorite",
"action.refresh": "Refresh",
+ "action.save": "Save",
"home.title": "Home",
"home.recentlyPlayed": "Recently Played",
"home.recentlyAdded": "Recently Added",
@@ -231,6 +232,7 @@
"error.connectionError": "There was a problem connecting to Apple Music.",
"error.noResults": "No Results.",
"error.noResults.description": "Try a new search.",
+ "error.musickitError": "MusicKit Encountered an Error: ",
"podcast.followOnCider": "Follow On Cider",
"podcast.followedOnCider": "Following On Cider",
"podcast.subscribeOnItunes": "Subscribe On iTunes",
@@ -249,6 +251,7 @@
"action.done": "Done",
"action.submit": "Submit",
"action.editTracklist": "Edit Tracklist",
+ "action.editDescription": "Edit Description",
"action.addToLibrary": "Add to Library",
"action.addToLibrary.success": "Added to Library",
"action.addToLibrary.error": "Error Adding to Library",
@@ -263,6 +266,7 @@
"action.createPlaylist": "Create a New Playlist",
"action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?",
"action.addToPlaylist": "Add to Playlist",
+ "action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?",
"action.removeFromPlaylist": "Remove from Playlist",
"action.addToFavorites": "Add to Favorites",
"action.follow": "Follow",
@@ -539,6 +543,7 @@
"settings.option.connectivity.discordRPC.buttons.viewOnAppleMusic": "View on Apple Music",
"settings.option.connectivity.discordRPC.buttons.viewOnOtherMusicServices": "View on Other Music Services",
"settings.option.connectivity.discordRPC.showSongLink": "Show Song.link button instead of Apple Music button on Discord Rich Presence",
+ "settings.option.connectivity.discordRPC.hideButtons": "Hide buttons on Discord Rich Presence",
"settings.option.connectivity.discordRPC.hideTimestamp": "Hide timestamp on Discord Rich Presence",
"settings.option.connectivity.discordRPC.detailsFormat": "Details Format",
"settings.option.connectivity.discordRPC.stateFormat": "State Format",
diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json
index 9163dd1b..38267fe3 100644
--- a/src/i18n/source/en_US.json
+++ b/src/i18n/source/en_US.json
@@ -219,6 +219,7 @@
"action.favorite": "Favorite",
"action.removeFavorite": "Remove Favorite",
"action.refresh": "Refresh",
+ "action.save": "Save",
"home.title": "Home",
"home.recentlyPlayed": "Recently Played",
"home.recentlyAdded": "Recently Added",
@@ -231,6 +232,7 @@
"error.connectionError": "There was a problem connecting to Apple Music.",
"error.noResults": "No Results.",
"error.noResults.description": "Try a new search.",
+ "error.musickitError": "MusicKit Encountered an Error: ",
"podcast.followOnCider": "Follow On Cider",
"podcast.followedOnCider": "Following On Cider",
"podcast.subscribeOnItunes": "Subscribe On iTunes",
@@ -249,6 +251,7 @@
"action.done": "Done",
"action.submit": "Submit",
"action.editTracklist": "Edit Tracklist",
+ "action.editDescription": "Edit Description",
"action.addToLibrary": "Add to Library",
"action.addToLibrary.success": "Added to Library",
"action.addToLibrary.error": "Error Adding to Library",
@@ -263,6 +266,7 @@
"action.createPlaylist": "Create a New Playlist",
"action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?",
"action.addToPlaylist": "Add to Playlist",
+ "action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?",
"action.removeFromPlaylist": "Remove from Playlist",
"action.addToFavorites": "Add to Favorites",
"action.follow": "Follow",
@@ -539,6 +543,7 @@
"settings.option.connectivity.discordRPC.buttons.viewOnAppleMusic": "View on Apple Music",
"settings.option.connectivity.discordRPC.buttons.viewOnOtherMusicServices": "View on Other Music Services",
"settings.option.connectivity.discordRPC.showSongLink": "Show Song.link button instead of Apple Music button on Discord Rich Presence",
+ "settings.option.connectivity.discordRPC.hideButtons": "Hide buttons on Discord Rich Presence",
"settings.option.connectivity.discordRPC.hideTimestamp": "Hide timestamp on Discord Rich Presence",
"settings.option.connectivity.discordRPC.detailsFormat": "Details Format",
"settings.option.connectivity.discordRPC.stateFormat": "State Format",
diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts
index c044894a..f0b4731a 100644
--- a/src/main/base/browserwindow.ts
+++ b/src/main/base/browserwindow.ts
@@ -1445,16 +1445,18 @@ export class BrowserWindow {
}
});
- win.on("close", (e: any) => {
+ win.on("close", async (e: any) => {
if ((process.platform === "darwin" || utils.getStoreValue("general.close_button_hide")) && !isQuitting) {
e.preventDefault();
win.hide();
} else {
- win.webContents.executeJavaScript(`
+ await 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','');`);
+ ipcRenderer.send('stopGCast','');
+ MusicKit.getInstance().stop();
+ `);
}
});
diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js
index afc3cf74..1314f33d 100644
--- a/src/preload/cider-preload.js
+++ b/src/preload/cider-preload.js
@@ -144,7 +144,7 @@ const MusicKitInterop = {
const attributes = nowPlayingItem != null ? nowPlayingItem.attributes : {};
attributes.songId = attributes.songId ?? attributes.playParams?.catalogId ?? attributes.playParams?.id;
- attributes.kind = nowPlayingItem?.type ?? attributes.type ?? attributes.playParams.kind ?? "";
+ attributes.kind = nowPlayingItem?.type ?? attributes?.type ?? attributes.playParams?.kind ?? "";
attributes.status = nowPlayingItem == null ? null : !!isPlayingExport;
attributes.name = attributes?.name ?? "no-title-found";
attributes.artwork = attributes?.artwork ?? { url: "" };
@@ -229,42 +229,38 @@ const MusicKitInterop = {
initMediaSession: () => {
if ("mediaSession" in navigator) {
- const defaultSkipTime = 10;
-
console.debug("[cider:preload] [initMediaSession] Media Session API supported");
navigator.mediaSession.setActionHandler("play", () => {
MusicKitInterop.play();
- console.log("[cider:preload] [initMediaSession] Play");
});
navigator.mediaSession.setActionHandler("pause", () => {
MusicKitInterop.pause();
- console.log("[cider:preload] [initMediaSession] Pause");
});
navigator.mediaSession.setActionHandler("stop", () => {
MusicKit.getInstance().stop();
- console.log("[cider:preload] [initMediaSession] Stop");
});
navigator.mediaSession.setActionHandler("seekbackward", (details) => {
- const skipTime = details.seekOffset || defaultSkipTime;
- MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime - skipTime, 0));
- console.log(`[cider:preload] [initMediaSession] Seek Backward ${skipTime}`);
+ if (details.seekOffset) {
+ MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime - details.seekOffset, 0));
+ } else {
+ MusicKit.getInstance().seekBackward();
+ }
});
navigator.mediaSession.setActionHandler("seekforward", (details) => {
- const skipTime = details.seekOffset || defaultSkipTime;
- MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime + skipTime, 0));
- console.log(`[cider:preload] [initMediaSession] Seek Forward ${skipTime}`);
+ if (details.seekOffset) {
+ MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime + details.seekOffset, 0));
+ } else {
+ MusicKit.getInstance().seekForward();
+ }
});
navigator.mediaSession.setActionHandler("seekto", ({ seekTime, fastSeek }) => {
MusicKit.getInstance().seekToTime(seekTime);
- console.log(`[cider:preload] [initMediaSession] Seek To ${seekTime}`);
});
navigator.mediaSession.setActionHandler("previoustrack", () => {
MusicKitInterop.previous();
- console.log("[cider:preload] [initMediaSession] Previous Track");
});
navigator.mediaSession.setActionHandler("nexttrack", () => {
MusicKitInterop.next();
- console.log("[cider:preload] [initMediaSession] Next Track");
});
} else {
console.debug("[cider:preload] [initMediaSession] Media Session API not supported");
diff --git a/src/renderer/audio/audio.js b/src/renderer/audio/audio.js
index 9a993c14..cbf84d1e 100644
--- a/src/renderer/audio/audio.js
+++ b/src/renderer/audio/audio.js
@@ -972,8 +972,6 @@ const CiderAudio = {
MusicKit.getInstance().pause(); // Pause first
}
- CiderAudioRenderer.off(); // Clean up IMMEDIATELY
-
CiderAudio.audioNodes.optimizedNode = CiderAudio.context.createConvolver();
CiderAudio.audioNodes.optimizedNode.normalize = false;
@@ -981,6 +979,8 @@ const CiderAudio = {
CiderAudio.audioNodes.optimizedNode.buffer = res;
});
+ CiderAudioRenderer.off(); // Clean up IMMEDIATELY
+
// Load the sucker up
CiderAudio.hierarchical_unloading();
diff --git a/src/renderer/main/ciderfrontapi.js b/src/renderer/main/ciderfrontapi.js
index 8a7ef76a..6b87ad3f 100644
--- a/src/renderer/main/ciderfrontapi.js
+++ b/src/renderer/main/ciderfrontapi.js
@@ -4,10 +4,15 @@ const CiderFrontAPI = {
this.id = "";
this.name = "";
this.onClick = () => {};
+ this.top = false;
},
},
AddMenuEntry(entry) {
- app.pluginMenuEntries.push(entry);
+ if (entry?.top) {
+ app.pluginMenuTopEntries.push(entry);
+ } else {
+ app.pluginMenuEntries.push(entry);
+ }
app.pluginInstalled = true;
},
StyleSheets: {
diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js
index 49b3606c..52fe2de6 100644
--- a/src/renderer/main/vueapp.js
+++ b/src/renderer/main/vueapp.js
@@ -18,6 +18,7 @@ const app = new Vue({
mk: {},
pluginInstalled: false,
pluginMenuEntries: [],
+ pluginMenuTopEntries: [],
lz: ipcRenderer.sendSync("get-i18n", "en_US"),
lzListing: ipcRenderer.sendSync("get-i18n-listing"),
radiohls: null,
@@ -305,6 +306,20 @@ const app = new Vue({
app.cfg.musickit["stored-attributes"][attr] = val;
});
}
+ const ERROR_CODES = ["drmUnsupported", "mediaPlaybackError"];
+ /* MusicKit.Events */
+ ERROR_CODES.forEach((code) => {
+ MusicKit.getInstance().addEventListener(MusicKit.Events[code], (e) => {
+ console.error(`[MusicKit] MusicKit Error ${code}`);
+ console.error({ e: e });
+ app.notyf.open({
+ duration: 20000,
+ type: "error",
+ className: "notyf-info",
+ message: `${app.getLz("error.musickitError")} \n${code.toUpperCase()}
`,
+ });
+ });
+ });
},
async oobeInit() {
this.appMode = "oobe";
diff --git a/src/renderer/views/app/app-navigation.ejs b/src/renderer/views/app/app-navigation.ejs
index 7e03c957..bf6da9dc 100644
--- a/src/renderer/views/app/app-navigation.ejs
+++ b/src/renderer/views/app/app-navigation.ejs
@@ -1,166 +1,151 @@