follow has been migrated to favorites

This commit is contained in:
booploops 2022-06-09 21:25:38 -07:00
parent 05b6ea112e
commit d7b314e0f5
9 changed files with 257 additions and 222 deletions

View file

@ -193,6 +193,8 @@
"term.confirmLogout": "Are you sure you want to logout?", "term.confirmLogout": "Are you sure you want to logout?",
"term.creditDesignedBy": "Designed by ${authorUsername}", "term.creditDesignedBy": "Designed by ${authorUsername}",
"term.discNumber": "Disc ${discNumber}", "term.discNumber": "Disc ${discNumber}",
"home.syncFavorites": "Sync Favorites",
"home.syncFavorites.gettingArtists": "Getting Favorited Artists...",
"home.title": "Home", "home.title": "Home",
"home.recentlyPlayed": "Recently Played", "home.recentlyPlayed": "Recently Played",
"home.recentlyAdded": "Recently Added", "home.recentlyAdded": "Recently Added",

View file

@ -1,4 +1,4 @@
import {store} from './vuex-store.js'; import { store } from './vuex-store.js';
Vue.use(VueHorizontal); Vue.use(VueHorizontal);
Vue.use(VueObserveVisibility); Vue.use(VueObserveVisibility);
@ -80,7 +80,7 @@ const app = new Vue({
sorting: "name", sorting: "name",
sortOrder: "asc", sortOrder: "asc",
listing: [], listing: [],
meta: {total: 0, progress: 0}, meta: { total: 0, progress: 0 },
search: "", search: "",
displayListing: [], displayListing: [],
downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library
@ -96,7 +96,7 @@ const app = new Vue({
sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page
sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page
listing: [], listing: [],
meta: {total: 0, progress: 0}, meta: { total: 0, progress: 0 },
search: "", search: "",
displayListing: [], displayListing: [],
downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library
@ -112,12 +112,12 @@ const app = new Vue({
sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page
sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page
listing: [], listing: [],
meta: {total: 0, progress: 0}, meta: { total: 0, progress: 0 },
search: "", search: "",
displayListing: [], displayListing: [],
downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library
}, },
localsongs : [] localsongs: []
}, },
playlists: { playlists: {
listing: [], listing: [],
@ -176,7 +176,7 @@ const app = new Vue({
"attributes": { "attributes": {
"name": "Cider User", "name": "Cider User",
"handle": "CiderUser", "handle": "CiderUser",
"artwork": {"url": "./assets/logocut.png"} "artwork": { "url": "./assets/logocut.png" }
} }
}, },
forceDirectives: {}, forceDirectives: {},
@ -285,10 +285,10 @@ const app = new Vue({
}, },
getAppStyle() { getAppStyle() {
let finalStyle = {} let finalStyle = {}
if(this.cfg.visual.window_background_style === "color") { if (this.cfg.visual.window_background_style === "color") {
finalStyle["background-color"] = this.cfg.visual.windowColor finalStyle["background-color"] = this.cfg.visual.windowColor
} }
if(this.cfg.visual.customAccentColor) { if (this.cfg.visual.customAccentColor) {
finalStyle["--keyColor"] = this.cfg.visual.accentColor finalStyle["--keyColor"] = this.cfg.visual.accentColor
finalStyle["--songProgressColor"] = this.cfg.visual.accentColor finalStyle["--songProgressColor"] = this.cfg.visual.accentColor
} }
@ -298,7 +298,7 @@ const app = new Vue({
return setTimeout(func, time); return setTimeout(func, time);
}, },
songLinkShare(amUrl) { songLinkShare(amUrl) {
notyf.open({type: "info", className: "notyf-info", message: app.getLz('term.song.link.generate')}) notyf.open({ type: "info", className: "notyf-info", message: app.getLz('term.song.link.generate') })
let self = this let self = this
let httpRequest = new XMLHttpRequest(); let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', `https://api.song.link/v1-alpha.1/links?url=${amUrl}&userCountry=US`, true); httpRequest.open('GET', `https://api.song.link/v1-alpha.1/links?url=${amUrl}&userCountry=US`, true);
@ -414,7 +414,7 @@ const app = new Vue({
}, },
async showSocialListeningTo() { async showSocialListeningTo() {
let contentIds = Object.keys(app.socialBadges.badgeMap) let contentIds = Object.keys(app.socialBadges.badgeMap)
app.showCollection({data: this.socialBadges.mediaItems}, "Friends Listening To", "albums") app.showCollection({ data: this.socialBadges.mediaItems }, "Friends Listening To", "albums")
if (this.socialBadges.mediaItemDLState == 1 || this.socialBadges.mediaItemDLState == 2) { if (this.socialBadges.mediaItemDLState == 1 || this.socialBadges.mediaItemDLState == 2) {
return return
} }
@ -512,11 +512,12 @@ const app = new Vue({
}) })
}, },
goToGrouping(url = "https://music.apple.com/WebObjects/MZStore.woa/wa/viewGrouping?cc=us&id=34") { goToGrouping(url = "https://music.apple.com/WebObjects/MZStore.woa/wa/viewGrouping?cc=us&id=34") {
if (url.includes('viewTop')){ if (url.includes('viewTop')) {
window.location.hash = `#charts/top` window.location.hash = `#charts/top`
} else { } else {
const id = url.split("id=")[1]; const id = url.split("id=")[1];
window.location.hash = `#groupings/${id}`} window.location.hash = `#groupings/${id}`
}
}, },
navigateForward() { navigateForward() {
history.forward() history.forward()
@ -558,7 +559,7 @@ const app = new Vue({
self.selectedMediaItems[i].kind = "albums" self.selectedMediaItems[i].kind = "albums"
let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`); let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`);
let ids = res.data.data.map(function (i) { let ids = res.data.data.map(function (i) {
return {id: i.id, type: i.type} return { id: i.id, type: i.type }
}) })
pl_items = pl_items.concat(ids) pl_items = pl_items.concat(ids)
} else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") {
@ -571,7 +572,7 @@ const app = new Vue({
self.selectedMediaItems[i].kind = "library-albums" self.selectedMediaItems[i].kind = "library-albums"
let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`); let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`);
let ids = res.data.data.map(function (i) { let ids = res.data.data.map(function (i) {
return {id: i.id, type: i.type} return { id: i.id, type: i.type }
}) })
pl_items = pl_items.concat(ids) pl_items = pl_items.concat(ids)
} else { } else {
@ -598,7 +599,7 @@ const app = new Vue({
self.selectedMediaItems[i].kind = "albums" self.selectedMediaItems[i].kind = "albums"
let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`); let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`);
let ids = res.data.data.map(function (i) { let ids = res.data.data.map(function (i) {
return {id: i.id, type: i.type} return { id: i.id, type: i.type }
}) })
pl_items = pl_items.concat(ids) pl_items = pl_items.concat(ids)
} else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") {
@ -611,7 +612,7 @@ const app = new Vue({
self.selectedMediaItems[i].kind = "library-albums" self.selectedMediaItems[i].kind = "library-albums"
let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`); let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`);
let ids = res.data.data.map(function (i) { let ids = res.data.data.map(function (i) {
return {id: i.id, type: i.type} return { id: i.id, type: i.type }
}) })
pl_items = pl_items.concat(ids) pl_items = pl_items.concat(ids)
} else { } else {
@ -640,7 +641,7 @@ const app = new Vue({
}, },
async init() { async init() {
let self = this let self = this
if(!localStorage.getItem("seenOOBE")) { if (!localStorage.getItem("seenOOBE")) {
localStorage.setItem("seenOOBE", 1) localStorage.setItem("seenOOBE", 1)
} }
if (this.cfg.visual.styles.length != 0) { if (this.cfg.visual.styles.length != 0) {
@ -704,7 +705,7 @@ const app = new Vue({
"attributes": { "attributes": {
"name": "Cider User", "name": "Cider User",
"handle": "CiderUser", "handle": "CiderUser",
"artwork": {"url": "./assets/logocut.png"} "artwork": { "url": "./assets/logocut.png" }
} }
} }
} }
@ -755,7 +756,7 @@ const app = new Vue({
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} parameters: { l: app.mklang }
}) })
app.mk.mute() app.mk.mute()
setTimeout(() => { setTimeout(() => {
@ -774,7 +775,7 @@ const app = new Vue({
for (let id of ids) { for (let id of ids) {
if (!(i == 0 && ids[0] == lastItem.attributes.playParams.id)) { if (!(i == 0 && ids[0] == lastItem.attributes.playParams.id)) {
try { try {
app.mk.playLater({songs: [id]}) app.mk.playLater({ songs: [id] })
} catch (err) { } catch (err) {
} }
} }
@ -796,14 +797,14 @@ const app = new Vue({
} }
break; break;
case "history": case "history":
let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, {l: app.mklang}) let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l: app.mklang })
if (history.data.data.length > 0) { if (history.data.data.length > 0) {
let lastItem = history.data.data[0] let lastItem = history.data.data[0]
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} parameters: { l: app.mklang }
}) })
app.mk.mute() app.mk.mute()
setTimeout(() => { setTimeout(() => {
@ -841,10 +842,11 @@ const app = new Vue({
user: `${user.username}#${user.discriminator}`, user: `${user.username}#${user.discriminator}`,
userid: user.id userid: user.id
})); }));
}}) }
})
ipcRenderer.on('getUpdatedLocalList', (event,data) => { ipcRenderer.on('getUpdatedLocalList', (event, data) => {
console.log("cider-local",data); console.log("cider-local", data);
this.library.localsongs = data; this.library.localsongs = data;
}) })
@ -885,7 +887,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, parameters: {l: self.mklang}}).then(() => { self.mk.setQueue({ [mode]: id, parameters: { l: self.mklang } }).then(() => {
app.mk.play() app.mk.play()
}) })
@ -1249,6 +1251,66 @@ const app = new Vue({
} }
}) })
}, },
async syncFavorites() {
const notify = notyf.open({
className: "notyf-info",
type: "info",
message: `[${app.getLz('home.syncFavorites')}] ${app.getLz('home.syncFavorites.gettingArtists')}`
})
const results = await MusicKitTools.v3Continuous({
href: "/v1/me/library/artists", options: {
"include": ["catalog"],
"fields[artists]": ["inFavorites"]
}
})
let favs = []
// for each result
results.forEach(result => {
try {
if (result.relationships?.catalog?.data[0]?.attributes?.inFavorites) {
if(!favs.includes(result.relationships?.catalog?.data[0].id)) {
favs.push(result.relationships?.catalog?.data[0].id)
}
}
} catch (e) {
e = null
}
})
notyf.success(`[${app.getLz('home.syncFavorites')}] ${app.getLz('action.done')}`)
app.cfg.home.followedArtists = favs
return favs
},
async setArtistFavorite(id, val = true) {
if(val) {
if(!app.cfg.home.followedArtists.includes(id)) {
app.cfg.home.followedArtists.push(id)
}
await app.mk.api.v3.music(`/v1/me/favorites`, {
"art[url]": "f",
"ids[artists]": app.artistPage.data.id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "POST"
}
})
}else{
if(app.cfg.home.followedArtists.includes(id)) {
app.cfg.home.followedArtists.splice(app.cfg.home.followedArtists.indexOf(id), 1)
}
await app.mk.api.v3.music(`/v1/me/favorites`, {
"art[url]": "f",
"ids[artists]": app.artistPage.data.id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "DELETE"
}
})
}
},
async refreshPlaylists(localOnly = false, useCachedPlaylists = true) { async refreshPlaylists(localOnly = false, useCachedPlaylists = true) {
let self = this let self = this
let trackMap = this.cfg.advanced.playlistTrackMapping let trackMap = this.cfg.advanced.playlistTrackMapping
@ -1282,7 +1344,7 @@ const app = new Vue({
async function deepScan(parent = "p.playlistsroot") { async function deepScan(parent = "p.playlistsroot") {
console.debug(`scanning ${parent}`) console.debug(`scanning ${parent}`)
// const playlistData = await app.mk.api.v3.music(`/v1/me/library/playlist-folders/${parent}/children/`) // const playlistData = await app.mk.api.v3.music(`/v1/me/library/playlist-folders/${parent}/children/`)
const playlistData = await MusicKitTools.v3Continuous({href: `/v1/me/library/playlist-folders/${parent}/children/`}) const playlistData = await MusicKitTools.v3Continuous({ href: `/v1/me/library/playlist-folders/${parent}/children/` })
console.log(playlistData) console.log(playlistData)
await asyncForEach(playlistData, async (playlist) => { await asyncForEach(playlistData, async (playlist) => {
playlist.parent = parent playlist.parent = parent
@ -1375,7 +1437,7 @@ const app = new Vue({
fetchOptions: { fetchOptions: {
method: "PATCH", method: "PATCH",
body: JSON.stringify({ body: JSON.stringify({
attributes: {name: name} attributes: { name: name }
}) })
} }
} }
@ -1390,7 +1452,7 @@ const app = new Vue({
fetchOptions: { fetchOptions: {
method: "PATCH", method: "PATCH",
body: JSON.stringify({ body: JSON.stringify({
attributes: {name: name} attributes: { name: name }
}) })
} }
} }
@ -1405,7 +1467,7 @@ const app = new Vue({
fetchOptions: { fetchOptions: {
method: "PATCH", method: "PATCH",
body: JSON.stringify({ body: JSON.stringify({
attributes: {description: name} attributes: { description: name }
}) })
} }
} }
@ -1433,9 +1495,9 @@ const app = new Vue({
fetchOptions: { fetchOptions: {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
"attributes": {"name": name}, "attributes": { "name": name },
"relationships": { "relationships": {
"tracks": {"data": tracks}, "tracks": { "data": tracks },
} }
}) })
} }
@ -1498,7 +1560,7 @@ 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}?l=${this.mklang}`, {}, {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.debug(response) console.debug(response)
await this.showCollection(response, title, "artists") await this.showCollection(response, title, "artists")
}, },
@ -1615,7 +1677,7 @@ const app = new Vue({
"limit[artists:top-songs]": 20, "limit[artists:top-songs]": 20,
"art[url]": "f", "art[url]": "f",
l: this.mklang l: this.mklang
}, {includeResponseMeta: !0}) }, { includeResponseMeta: !0 })
console.debug(artistData.data.data[0]) console.debug(artistData.data.data[0])
this.artistPage.data = artistData.data.data[0] this.artistPage.data = artistData.data.data[0]
this.page = "artist-page" this.page = "artist-page"
@ -1698,9 +1760,9 @@ const app = new Vue({
const m = Math.floor(seconds % 3600 / 60); const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 60); const s = Math.floor(seconds % 60);
const dDisplay = d > 0 ? `${d} ${app.getLz("term.time.day", {"count": d})}` : ""; const dDisplay = d > 0 ? `${d} ${app.getLz("term.time.day", { "count": d })}` : "";
const hDisplay = h > 0 ? `${h} ${app.getLz("term.time.hour", {"count": h})}` : ""; const hDisplay = h > 0 ? `${h} ${app.getLz("term.time.hour", { "count": h })}` : "";
const mDisplay = m > 0 ? `${m} ${app.getLz("term.time.minute", {"count": m})}` : ""; const mDisplay = m > 0 ? `${m} ${app.getLz("term.time.minute", { "count": m })}` : "";
return dDisplay + (dDisplay && hDisplay ? ", " : "") + hDisplay + (hDisplay && mDisplay ? ", " : "") + mDisplay; return dDisplay + (dDisplay && hDisplay ? ", " : "") + hDisplay + (hDisplay && mDisplay ? ", " : "") + mDisplay;
} else { } else {
@ -1772,7 +1834,7 @@ const app = new Vue({
kind: page, kind: page,
id: id, id: id,
attributes: { attributes: {
playParams: {kind: page, id: id, isLibrary: isLibrary} playParams: { kind: page, id: id, isLibrary: isLibrary }
} }
}) })
}, },
@ -1919,7 +1981,7 @@ const app = new Vue({
let u = await app.mkapi(app.mk.nowPlayingItem.playParams.kind, let u = await app.mkapi(app.mk.nowPlayingItem.playParams.kind,
(app.mk.nowPlayingItem.songId == -1), (app.mk.nowPlayingItem.songId == -1),
(app.mk.nowPlayingItem.songId != -1) ? app.mk.nowPlayingItem.songId : app.mk.nowPlayingItem["id"], (app.mk.nowPlayingItem.songId != -1) ? app.mk.nowPlayingItem.songId : app.mk.nowPlayingItem["id"],
{"include[songs]": "albums,artists", l: app.mklang}); { "include[songs]": "albums,artists", l: app.mklang });
app.searchAndNavigate(u.data.data[0], target) app.searchAndNavigate(u.data.data[0], target)
} catch (e) { } catch (e) {
app.searchAndNavigate(app.mk.nowPlayingItem, target) app.searchAndNavigate(app.mk.nowPlayingItem, target)
@ -2023,7 +2085,7 @@ const app = new Vue({
} }
if (labelId != "") { if (labelId != "") {
app.showingPlaylist = [] app.showingPlaylist = []
await app.getTypeFromID("recordLabel", labelId, false, {views: 'top-releases,latest-releases,top-artists'}); await app.getTypeFromID("recordLabel", labelId, false, { views: 'top-releases,latest-releases,top-artists' });
app.page = "recordLabel_" + labelId; app.page = "recordLabel_" + labelId;
} }
@ -2038,16 +2100,6 @@ const app = new Vue({
this.getArtistFromID(id) this.getArtistFromID(id)
//this.getTypeFromID("artist",id,isLibrary,query) //this.getTypeFromID("artist",id,isLibrary,query)
}, },
followArtistById(id, follow) {
if (follow && !this.followingArtist(id)) {
this.cfg.home.followedArtists.push(id)
} else {
let index = this.cfg.home.followedArtists.indexOf(id)
if (index > -1) {
this.cfg.home.followedArtists.splice(index, 1)
}
}
},
followingArtist(id) { followingArtist(id) {
console.debug(`check for ${id}`) console.debug(`check for ${id}`)
return this.cfg.home.followedArtists.includes(id) return this.cfg.home.followedArtists.includes(id)
@ -2061,7 +2113,7 @@ const app = new Vue({
// console.log(kind, id, isLibrary) // console.log(kind, id, isLibrary)
app.mk.stop().then(() => { app.mk.stop().then(() => {
if (kind.includes("artist")) { if (kind.includes("artist")) {
app.mk.setStationQueue({artist: 'a-' + id}).then(() => { app.mk.setStationQueue({ artist: 'a-' + id }).then(() => {
app.mk.play() app.mk.play()
}) })
} else { } else {
@ -2108,7 +2160,7 @@ const app = new Vue({
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) { let albumAdded = self.library?.albums?.listing?.map(function (i) {
return {[i.id]: i.attributes?.dateAdded} return { [i.id]: i.attributes?.dateAdded }
}) })
let startTime = new Date().getTime() let startTime = new Date().getTime()
@ -2647,19 +2699,19 @@ const app = new Vue({
getTotalTime() { getTotalTime() {
try { try {
if (app.showingPlaylist.relationships.tracks.data.length === 0) return "" if (app.showingPlaylist.relationships.tracks.data.length === 0) return ""
const timeInSeconds = Math.round([].concat(...app.showingPlaylist.relationships.tracks.data).reduce((a, {attributes: {durationInMillis}}) => a + durationInMillis, 0) / 1000); const timeInSeconds = Math.round([].concat(...app.showingPlaylist.relationships.tracks.data).reduce((a, { attributes: { durationInMillis } }) => a + durationInMillis, 0) / 1000);
return `${app.showingPlaylist.relationships.tracks.data.length} ${app.getLz("term.track", {"count": app.showingPlaylist.relationships.tracks.data.length})}, ${app.convertTime(timeInSeconds, 'long')}` return `${app.showingPlaylist.relationships.tracks.data.length} ${app.getLz("term.track", { "count": app.showingPlaylist.relationships.tracks.data.length })}, ${app.convertTime(timeInSeconds, 'long')}`
} catch (err) { } catch (err) {
return "" return ""
} }
}, },
async getLibrarySongs() { async getLibrarySongs() {
let response = await this.mkapi("songs", true, "", {limit: 100, l: this.mklang}, {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, l: this.mklang}, {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
}, },
@ -2753,7 +2805,7 @@ const app = new Vue({
fetchOptions: { fetchOptions: {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
attributes: {name: name} attributes: { name: name }
}) })
} }
} }
@ -3272,15 +3324,15 @@ const app = new Vue({
line: "lrcInstrumental" line: "lrcInstrumental"
}); });
} }
preLrc.push({startTime: start, endTime: end, line: element.textContent}); preLrc.push({ startTime: start, endTime: end, line: element.textContent });
endTimes.push(end); endTimes.push(end);
} }
// first line dot // first line dot
if (preLrc.length > 0) if (preLrc.length > 0)
preLrc.unshift({startTime: 0, endTime: preLrc[0].startTime, line: "lrcInstrumental"}); preLrc.unshift({ startTime: 0, endTime: preLrc[0].startTime, line: "lrcInstrumental" });
} else { } else {
for (let element of lyricsLines) { for (let element of lyricsLines) {
preLrc.push({startTime: 9999999, endTime: 9999999, line: element.textContent}); preLrc.push({ startTime: 9999999, endTime: 9999999, line: element.textContent });
} }
} }
this.lyrics = preLrc; this.lyrics = preLrc;
@ -3348,17 +3400,17 @@ const app = new Vue({
console.debug(id, truekind, isLibrary) console.debug(id, truekind, isLibrary)
try { try {
if (truekind.includes("artist")) { if (truekind.includes("artist")) {
app.mk.setStationQueue({artist: 'a-' + id}).then(() => { app.mk.setStationQueue({ artist: 'a-' + id }).then(() => {
app.mk.play() app.mk.play()
}) })
} else if (truekind == "radioStations") { } else if (truekind == "radioStations") {
this.mk.setStationQueue({url: raurl}).then(function (queue) { this.mk.setStationQueue({ url: raurl }).then(function (queue) {
MusicKit.getInstance().play() MusicKit.getInstance().play()
}); });
} else { } else {
this.mk.setQueue({ this.mk.setQueue({
[truekind]: [id], [truekind]: [id],
parameters: {l: this.mklang} parameters: { l: this.mklang }
}).then(function (queue) { }).then(function (queue) {
MusicKit.getInstance().play() MusicKit.getInstance().play()
}) })
@ -3399,7 +3451,7 @@ const app = new Vue({
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} 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) {
@ -3456,7 +3508,7 @@ const app = new Vue({
for (let kind in itemsToPlay) { for (let kind in itemsToPlay) {
let ids = itemsToPlay[kind] let ids = itemsToPlay[kind]
if (ids.length > 0) { if (ids.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]}) app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] })
} }
} }
}) })
@ -3477,7 +3529,7 @@ const app = new Vue({
let ids = itemsToPlay[kind] let ids = itemsToPlay[kind]
if (ids.length > 0) { if (ids.length > 0) {
if (app.mk.queue._itemIDs.length > 0) { if (app.mk.queue._itemIDs.length > 0) {
app.mk.playLater({[kind + "s"]: itemsToPlay[kind]}).then(function () { app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] }).then(function () {
ind += 1; ind += 1;
console.log(ind, Object.keys(itemsToPlay).length) console.log(ind, Object.keys(itemsToPlay).length)
if (ind >= Object.keys(itemsToPlay).length) { if (ind >= Object.keys(itemsToPlay).length) {
@ -3486,7 +3538,7 @@ const app = new Vue({
} }
) )
} else { } else {
app.mk.setQueue({[kind + "s"]: itemsToPlay[kind]}).then(function () { app.mk.setQueue({ [kind + "s"]: itemsToPlay[kind] }).then(function () {
ind += 1; ind += 1;
console.log(ind, Object.keys(itemsToPlay).length) console.log(ind, Object.keys(itemsToPlay).length)
if (ind >= Object.keys(itemsToPlay).length) { if (ind >= Object.keys(itemsToPlay).length) {
@ -3505,7 +3557,7 @@ const app = new Vue({
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} 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)) {
@ -3545,7 +3597,7 @@ const app = new Vue({
} else { } else {
this.mk.setQueue({ this.mk.setQueue({
[truekind]: [id], [truekind]: [id],
parameters: {l: this.mklang} 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)
@ -3669,7 +3721,7 @@ const app = new Vue({
with: ["serverBubbles", "lyricSnippet"], with: ["serverBubbles", "lyricSnippet"],
"art[url]": "f", "art[url]": "f",
"art[social-profiles:url]": "c" "art[social-profiles:url]": "c"
}, {includeResponseMeta: !0}).then(function (results) { }, { includeResponseMeta: !0 }).then(function (results) {
results.data.results["meta"] = results.data.meta results.data.results["meta"] = results.data.meta
self.search.resultsSocial = results.data.results self.search.resultsSocial = results.data.results
}) })
@ -3696,7 +3748,7 @@ const app = new Vue({
return type.type == this return type.type == this
}, type) }, type)
if (index == -1) { if (index == -1) {
types.push({type: type, id: [id]}) types.push({ type: type, id: [id] })
} else { } else {
types[index].id.push(id) types[index].id.push(id)
} }
@ -3900,10 +3952,10 @@ 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({ MusicKit.getInstance().setQueue({
song: data["songs"]['data'][0]["id"], song: data["songs"]['data'][0]["id"],
parameters: {l: app.mklang} parameters: { l: app.mklang }
}).then(function (queue) { }).then(function (queue) {
MusicKit.getInstance().play() MusicKit.getInstance().play()
setTimeout(() => { setTimeout(() => {
@ -4088,7 +4140,7 @@ const app = new Vue({
let data_type = this.mk.nowPlayingItem.playParams.kind let data_type = this.mk.nowPlayingItem.playParams.kind
let item_id = this.mk.nowPlayingItem.attributes.playParams.id ?? this.mk.nowPlayingItem.id let item_id = this.mk.nowPlayingItem.attributes.playParams.id ?? this.mk.nowPlayingItem.id
let isLibrary = this.mk.nowPlayingItem.attributes.playParams.isLibrary ?? false let isLibrary = this.mk.nowPlayingItem.attributes.playParams.isLibrary ?? false
let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "t": "1"} let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "t": "1" }
app.selectedMediaItems = [] app.selectedMediaItems = []
app.select_selectMediaItem(item_id, data_type, 0, '12344', isLibrary) app.select_selectMediaItem(item_id, data_type, 0, '12344', isLibrary)
let useMenu = "normal" let useMenu = "normal"
@ -4168,7 +4220,7 @@ const app = new Vue({
"icon": "./assets/feather/radio.svg", "icon": "./assets/feather/radio.svg",
"name": app.getLz('action.startRadio'), "name": app.getLz('action.startRadio'),
"action": function () { "action": function () {
app.mk.setStationQueue({song: app.mk.nowPlayingItem.id}).then(() => { app.mk.setStationQueue({ song: app.mk.nowPlayingItem.id }).then(() => {
app.mk.play() app.mk.play()
app.selectedMediaItems = [] app.selectedMediaItems = []
}) })
@ -4529,4 +4581,4 @@ const app = new Vue({
}) })
export {app} export { app }

View file

@ -6,8 +6,8 @@
<div class="artist-chip__name"> <div class="artist-chip__name">
<span>{{ item.attributes.name }}</span> <span>{{ item.attributes.name }}</span>
</div> </div>
<button @click="$root.followArtistById(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button> <button @click="$root.setArtistFavorite(artist.id, true)" title="Follow" v-if="!$root.followingArtist(artist.id)" class="artist-chip__follow codicon codicon-add"></button>
<button @click="$root.followArtistById(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button> <button @click="$root.setArtistFavorite(artist.id, false)" title="Following" v-else class="artist-chip__follow codicon codicon-check"></button>
</div> </div>
</script> </script>

View file

@ -534,19 +534,16 @@
let followActions = { let followActions = {
follow: { follow: {
icon: "./assets/feather/plus-circle.svg", icon: "./assets/feather/plus-circle.svg",
name: app.getLz('action.follow'), name: app.getLz('action.favorite'),
action: () => { action: () => {
self.app.cfg.home.followedArtists.push(this.item.id) self.$root.setArtistFavorite(this.item.id, true)
} }
}, },
unfollow: { unfollow: {
icon: "./assets/feather/x-circle.svg", icon: "./assets/feather/x-circle.svg",
name: app.getLz('action.unfollow'), name: app.getLz('action.removeFavorite'),
action: () => { action: () => {
let index = self.app.cfg.home.followedArtists.indexOf(this.item.id) self.$root.setArtistFavorite(this.item.id, false)
if (index > -1) {
self.app.cfg.home.followedArtists.splice(index, 1)
}
} }
} }
} }

View file

@ -7,6 +7,10 @@
<div class="col nopadding"> <div class="col nopadding">
<h3>{{app.getLz('home.followedArtists')}}</h3> <h3>{{app.getLz('home.followedArtists')}}</h3>
</div> </div>
<div class="col-auto nopadding flex-center">
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
<div class="spinner" style="height: 26px;" v-else></div>
</div>
</div> </div>
<vue-horizontal> <vue-horizontal>
<div v-for="artist in artists" style="margin: 6px;"> <div v-for="artist in artists" style="margin: 6px;">
@ -14,7 +18,7 @@
<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;">
<div class="sidebar-icon"> <div class="sidebar-icon">
<div class="svg-icon" :style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div> <div class="svg-icon" :style="{'--url': 'url(./assets/feather/x-circle.svg)'}"></div>
</div> {{app.getLz('action.unfollow')}} </div> {{app.getLz('action.removeFavorite')}}
</button> </button>
</div> </div>
</vue-horizontal> </vue-horizontal>
@ -53,7 +57,8 @@
app: this.$root, app: this.$root,
followedArtists: this.$root.cfg.home.followedArtists, followedArtists: this.$root.cfg.home.followedArtists,
artistFeed: [], artistFeed: [],
artists: [] artists: [],
syncingFavs: false
} }
}, },
async mounted() { async mounted() {
@ -61,7 +66,13 @@
await this.getArtistFeed() await this.getArtistFeed()
}, },
methods: { methods: {
unfollow(id) { async syncFavorites() {
this.syncingFavs = true
await app.syncFavorites()
await this.getArtistFeed()
this.syncingFavs = false
},
async unfollow(id) {
let index = this.followedArtists.indexOf(id) let index = this.followedArtists.indexOf(id)
if (index > -1) { if (index > -1) {
this.followedArtists.splice(index, 1) this.followedArtists.splice(index, 1)
@ -71,6 +82,16 @@
if (index2 > -1) { if (index2 > -1) {
this.artists.splice(index2, 1) this.artists.splice(index2, 1)
} }
await app.mk.api.v3.music(`/v1/me/favorites`, {
"art[url]": "f",
"ids[artists]": id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "DELETE"
}
})
this.getArtistFeed() this.getArtistFeed()
}, },
async getArtistFeed() { async getArtistFeed() {

View file

@ -194,32 +194,14 @@
icon: "./assets/star.svg", icon: "./assets/star.svg",
name: app.getLz('action.favorite'), name: app.getLz('action.favorite'),
action: () => { action: () => {
app.mk.api.v3.music(`/v1/me/favorites`, { app.setArtistFavorite(app.artistPage.data.id, true)
"art[url]": "f",
"ids[artists]": app.artistPage.data.id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "POST"
}
})
} }
}, },
removeFavorite: { removeFavorite: {
icon: "./assets/star.svg", icon: "./assets/star.svg",
name: app.getLz('action.removeFavorite'), name: app.getLz('action.removeFavorite'),
action: () => { action: () => {
app.mk.api.v3.music(`/v1/me/favorites`, { app.setArtistFavorite(app.artistPage.data.id, false)
"art[url]": "f",
"ids[artists]": app.artistPage.data.id,
"l": app.mklang,
"platform": "web"
}, {
fetchOptions: {
method: "DELETE"
}
})
} }
} }
} }
@ -241,7 +223,7 @@
} }
}, },
favoriteActions[inFavorites ? "removeFavorite" : "favorite"], favoriteActions[inFavorites ? "removeFavorite" : "favorite"],
followActions[followAction], // followActions[followAction],
{ {
icon: "./assets/feather/share.svg", icon: "./assets/feather/share.svg",
name: app.getLz('term.share'), name: app.getLz('term.share'),

View file

@ -643,39 +643,11 @@
app.copyToClipboard(res.data.data[0].attributes.url) app.copyToClipboard(res.data.data[0].attributes.url)
}) })
} }
},
"follow": {
name: app.getLz('action.follow'),
icon: "./assets/feather/plus-circle.svg",
hidden: false,
action: () => {
app.followArtistById(artistId, true)
} }
},
"unfollow": {
name: app.getLz('action.unfollow'),
icon: "./assets/feather/x-circle.svg",
hidden: true,
action: () => {
app.followArtistById(artistId, false)
}
},
} }
} }
app.showMenuPanel(menuItems, event) app.showMenuPanel(menuItems, event)
if (artistId != null) {
if (app.followingArtist(artistId)) {
menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = false
} else {
menuItems.items.follow.hidden = false
menuItems.items.unfollow.hidden = true
}
} else {
menuItems.items.follow.hidden = true
menuItems.items.unfollow.hidden = true
}
try { try {
let rating = await app.getRating(self.data) let rating = await app.getRating(self.data)
if (rating == 0) { if (rating == 0) {

View file

@ -26,6 +26,8 @@
<h3>{{app.getLz('home.artistsFeed')}}</h3> <h3>{{app.getLz('home.artistsFeed')}}</h3>
</div> </div>
<div class="col-auto nopadding flex-center"> <div class="col-auto nopadding flex-center">
<button class="cd-btn-seeall" @click="syncFavorites()" v-if="!syncingFavs">{{app.getLz('home.syncFavorites')}}</button>
<div class="spinner" style="height: 26px;" v-else></div>
<button class="cd-btn-seeall" @click="app.appRoute('artist-feed')">{{app.getLz('term.seeAll')}}</button> <button class="cd-btn-seeall" @click="app.appRoute('artist-feed')">{{app.getLz('term.seeAll')}}</button>
</div> </div>
</div> </div>
@ -113,7 +115,8 @@
page: "main", page: "main",
sectionsReady: [], sectionsReady: [],
year: new Date().getFullYear(), year: new Date().getFullYear(),
seenReplay: localStorage.getItem('seenReplay') seenReplay: localStorage.getItem('seenReplay'),
syncingFavs: false
} }
}, },
async mounted() { async mounted() {
@ -128,6 +131,12 @@
} }
}, },
methods: { methods: {
async syncFavorites() {
this.syncingFavs = true
await app.syncFavorites()
await this.getArtistFeed()
this.syncingFavs = false
},
async seeAllRecentlyPlayed() { async seeAllRecentlyPlayed() {
let hist = await app.mk.api.v3.music(`/v1/me/recent/played`, { let hist = await app.mk.api.v3.music(`/v1/me/recent/played`, {
l: this.$root.mklang, l: this.$root.mklang,
@ -188,7 +197,7 @@
async getArtistFeed() { async getArtistFeed() {
let artists = this.followedArtists let artists = this.followedArtists
let self = this let self = this
this.artistFeed = []
let chunks = [] let chunks = []
for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) { for (let artistIdx = 0; artistIdx < artists.length; artistIdx += 50) {
chunks.push(artists.slice(artistIdx, artistIdx + 50)); chunks.push(artists.slice(artistIdx, artistIdx + 50));

View file

@ -539,7 +539,7 @@
icon: "./assets/feather/plus-circle.svg", icon: "./assets/feather/plus-circle.svg",
hidden: false, hidden: false,
action: () => { action: () => {
app.followArtistById(artistId, true) app.setArtistFavorite(artistId, true)
} }
}, },
"unfollow": { "unfollow": {
@ -547,7 +547,7 @@
icon: "./assets/feather/x-circle.svg", icon: "./assets/feather/x-circle.svg",
hidden: true, hidden: true,
action: () => { action: () => {
app.followArtistById(artistId, false) app.setArtistFavorite(artistId, false)
} }
}, },
} }