diff --git a/dist/spicetify-playlist-labels.js b/dist/spicetify-playlist-labels.js index 1f267c8..11f209b 100644 --- a/dist/spicetify-playlist-labels.js +++ b/dist/spicetify-playlist-labels.js @@ -1,3 +1,3 @@ -!async function(){for(;!Spicetify.React||!Spicetify.ReactDOM;)await new Promise(t=>setTimeout(t,10));var o,c,s,p,u,m,t,e,i,r,n,a,l,d,f,y,v,h,b,g,w,x,k;o=Object.create,c=Object.defineProperty,s=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,u=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,i=(t=(t,e)=>function(){return e||(0,t[p(t)[0]])((e={exports:{}}).exports,e),e.exports})({"external-global-plugin:react-dom"(t,e){e.exports=Spicetify.ReactDOM}}),r=(e=(t,e,i)=>{i=null!=t?o(u(t)):{};var a=!e&&t&&t.__esModule?i:c(i,"default",{value:t,enumerable:!0}),l=t,r=void 0,n=void 0;if(l&&"object"==typeof l||"function"==typeof l)for(let t of p(l))m.call(a,t)||t===r||c(a,t,{get:()=>l[t],enumerable:!(n=s(l,t))||n.enumerable});return a})(t({"external-global-plugin:react"(t,e){e.exports=Spicetify.React}})()),n=e(i()),f=[],y=[],b=h=!(v={}),w=g=d=l=a=null,x=0,k=async function(){for(;null==Spicetify||!Spicetify.showNotification;)await new Promise(t=>setTimeout(t,100));b=await JSON.parse(localStorage.getItem("spicetify-playlist-labels:show-all")||"false");const t=()=>{L().then(t=>{v=t,h=!0,P()})};await Spicetify.Platform.RootlistAPI.getEvents().addListener("update",()=>{t()}),await Spicetify.Platform.LibraryAPI.getEvents().addListener("update",()=>{t()});var e=`${Spicetify.SVGIcons.spotify}`,e=(new Spicetify.Playbar.Button("Show All Saved Playlists",e,t=>{t.active=b=!t.active,localStorage.setItem("spicetify-playlist-labels:show-all",JSON.stringify(b)),h=!0,P()},!1,b),v=await L(),d=new MutationObserver(()=>{P()}),new MutationObserver(async()=>{await E()}));await E(),e.observe(document.body,{childList:!0,subtree:!0})},(async()=>{await k()})();function S(t){let i=[];return function e(t){"playlist"===t.type?i.push(t):"folder"===t.type&&t.items&&t.items.forEach(t=>e(t))}(t),i}async function L(){const a=S(await Spicetify.Platform.RootlistAPI.getContents());var t=await Promise.all(a.map(t=>async function(t){return(await Spicetify.Platform.PlaylistAPI.getContents(t)).items}(t.uri)));const l={};var e=await Spicetify.Platform.LibraryAPI.getTracks({limit:Number.MAX_SAFE_INTEGER});return t.forEach((t,i)=>{t.forEach(t=>{var e=t.uri;l[e]||(l[e]=[]),l[e].some(t=>t.uri===a[i].uri)||l[e].push({uri:a[i].uri,name:a[i].name,trackUid:t.uid,image:(null==(e=a[i].images[0])?void 0:e.url)||"",isOwnPlaylist:a[i].isOwnedBySelf,isLikedTracks:!1})})}),e.items.forEach(t=>{var e=t.uri;l[e]||(l[e]=[]),l[e].some(t=>t.isLikedTracks)||l[e].push({uri:null,name:"Liked Songs",trackUid:t.uid,image:"https://misc.scdn.co/liked-songs/liked-songs-300.png",isOwnPlaylist:!0,isLikedTracks:!0})}),l}function P(){var e,i;y=f,f=Array.from(document.querySelectorAll(".main-trackList-indexable")),y.length===f.length&&y.every((t,e)=>t===f[e])||(x=0);for(const t of f){for(const a of t.getElementsByClassName("main-trackList-trackListRow")){e=a,i=void 0;const l=(e=Object.values(e))?(null==(i=null==(e=null==(e=null==(e=null==(e=null==(e=e[0])?void 0:e.pendingProps)?void 0:e.children[0])?void 0:e.props)?void 0:e.children)?void 0:e.props)?void 0:i.uri)||(null==(i=null==(i=null==(i=null==e?void 0:e.props)?void 0:i.children)?void 0:i.props)?void 0:i.uri)||(null==(i=null==(i=null==(i=null==(i=null==(i=null==e?void 0:e.props)?void 0:i.children)?void 0:i.props)?void 0:i.children)?void 0:i.props)?void 0:i.uri)||(null==(e=null==(i=e[0])?void 0:i.props)?void 0:e.uri):null;g===l&&Spicetify.Platform.History.location.pathname===w&&(a.click(),g=null),(null==(i=v[l])?void 0:i.length)>x&&(x=null==(e=v[l])?void 0:e.length,document.documentElement.style.setProperty("--spicetify-playlist-labels-label-count",""+x));let t=a.querySelector(".spicetify-playlist-labels");h&&t&&(t.remove(),t=null),t||(i=a.querySelector(".main-trackList-rowSectionEnd"),(t=document.createElement("div")).classList.add("spicetify-playlist-labels"),n.default.render(r.default.createElement("div",{className:"spicetify-playlist-labels-labels-container"},null==(e=v[l])?void 0:e.map(e=>{if(!b&&!e.isOwnPlaylist)return null;if(e.isLikedTracks){if("/collection/tracks"===Spicetify.Platform.History.location.pathname)return null}else{var t=e.uri.match(/spotify:playlist:(.*)/)[1];if(Spicetify.Platform.History.location.pathname==="/playlist/"+t)return null}return r.default.createElement(Spicetify.ReactComponent.TooltipWrapper,{label:e.name,placement:"top"},r.default.createElement("div",null,r.default.createElement(Spicetify.ReactComponent.RightClickMenu,{placement:"bottom-end",menu:e.isLikedTracks?null:r.default.createElement(Spicetify.ReactComponent.Menu,null,r.default.createElement(Spicetify.ReactComponent.MenuItem,{leadingIcon:r.default.createElement(Spicetify.ReactComponent.IconComponent,{semanticColor:"textBase",dangerouslySetInnerHTML:{__html:''},iconSize:16}),onClick:t=>{t.stopPropagation(),async function(t,e){await Spicetify.Platform.PlaylistAPI.remove(t,[{uri:e,uid:""}])}(e.uri,l),v[l]=v[l].filter(t=>t.uri!==e.uri),h=!0,P()}},"Remove from ",e.name))},r.default.createElement("div",{className:"spicetify-playlist-labels-label-container",style:{cursor:"pointer"},onClick:t=>{t.stopPropagation();t=e.isLikedTracks?"/collection/tracks":null==(t=Spicetify.URI.fromString(e.uri))?void 0:t.toURLPath(!0);g=l,(w=t)&&Spicetify.Platform.History.push({pathname:t,search:"?uid="+e.trackUid})}},r.default.createElement("img",{src:e.image})))))})),t),i.insertBefore(t,i.firstChild))}h=!1}}async function E(){a=l,(l=document.querySelector("main"))&&!l.isEqualNode(a)&&(a&&d.disconnect(),P(),d.observe(l,{childList:!0,subtree:!0}))}(async()=>{var t;document.getElementById("spicetifyDplaylistDlabels")||((t=document.createElement("style")).id="spicetifyDplaylistDlabels",t.textContent=String.raw` +!async function(){for(;!Spicetify.React||!Spicetify.ReactDOM;)await new Promise(t=>setTimeout(t,10));var o,c,s,p,u,m,t,e,i,r,n,a,l,d,f,y,v,h,b,g,w,x,k;o=Object.create,c=Object.defineProperty,s=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,u=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,i=(t=(t,e)=>function(){return e||(0,t[p(t)[0]])((e={exports:{}}).exports,e),e.exports})({"external-global-plugin:react-dom"(t,e){e.exports=Spicetify.ReactDOM}}),r=(e=(t,e,i)=>{i=null!=t?o(u(t)):{};var a=!e&&t&&t.__esModule?i:c(i,"default",{value:t,enumerable:!0}),l=t,r=void 0,n=void 0;if(l&&"object"==typeof l||"function"==typeof l)for(let t of p(l))m.call(a,t)||t===r||c(a,t,{get:()=>l[t],enumerable:!(n=s(l,t))||n.enumerable});return a})(t({"external-global-plugin:react"(t,e){e.exports=Spicetify.React}})()),n=e(i()),f=[],y=[],b=h=!(v={}),w=g=d=l=a=null,x=0,k=async function(){for(;null==Spicetify||!Spicetify.showNotification;)await new Promise(t=>setTimeout(t,100));b=await JSON.parse(localStorage.getItem("spicetify-playlist-labels:show-all")||"false");const t=()=>{L().then(t=>{v=t,h=!0,P()})};await Spicetify.Platform.RootlistAPI.getEvents().addListener("update",()=>{t()}),await Spicetify.Platform.LibraryAPI.getEvents().addListener("update",()=>{t()});var e=`${Spicetify.SVGIcons.spotify}`,e=(new Spicetify.Playbar.Button("Show All Saved Playlists",e,t=>{t.active=b=!t.active,localStorage.setItem("spicetify-playlist-labels:show-all",JSON.stringify(b)),h=!0,P()},!1,b),v=await L(),d=new MutationObserver(()=>{P()}),new MutationObserver(async()=>{await E()}));await E(),e.observe(document.body,{childList:!0,subtree:!0})},(async()=>{await k()})();function S(t){let a=[],l=[];return function e(i,t){"playlist"===i.type?(t?l:a).push(i):"folder"===i.type&&i.items&&i.items.forEach(t=>e(t,"Rated"==i.name))}(t,!1),[a,l]}async function L(){var[t,e]=S(await Spicetify.Platform.RootlistAPI.getContents()),i=await Promise.all([...t,...e].map(t=>async function(t){return(await Spicetify.Platform.PlaylistAPI.getContents(t)).items}(t.uri))),a=i.slice(0,t.length),i=i.slice(t.length);const l={};var r=await Spicetify.Platform.LibraryAPI.getTracks({limit:Number.MAX_SAFE_INTEGER});function n(a,t){t.forEach((t,i)=>{t.forEach(t=>{var e=t.uri;l[e]||(l[e]=[]),l[e].some(t=>t.uri===a[i].uri)||l[e].push({uri:a[i].uri,name:a[i].name,trackUid:t.uid,image:(null==(e=a[i].images[0])?void 0:e.url)||"",isOwnPlaylist:a[i].isOwnedBySelf,isLikedTracks:!1})})})}return n(t,a),r.items.forEach(t=>{var e=t.uri;l[e]||(l[e]=[]),l[e].some(t=>t.isLikedTracks)||l[e].push({uri:null,name:"Liked Songs",trackUid:t.uid,image:"https://misc.scdn.co/liked-songs/liked-songs-300.png",isOwnPlaylist:!0,isLikedTracks:!0})}),n(e,i),l}function P(){var e,i;y=f,f=Array.from(document.querySelectorAll(".main-trackList-indexable")),y.length===f.length&&y.every((t,e)=>t===f[e])||(x=0);for(const t of f){for(const a of t.getElementsByClassName("main-trackList-trackListRow")){e=a,i=void 0;const l=(e=Object.values(e))?(null==(i=null==(e=null==(e=null==(e=null==(e=null==(e=e[0])?void 0:e.pendingProps)?void 0:e.children[0])?void 0:e.props)?void 0:e.children)?void 0:e.props)?void 0:i.uri)||(null==(i=null==(i=null==(i=null==e?void 0:e.props)?void 0:i.children)?void 0:i.props)?void 0:i.uri)||(null==(i=null==(i=null==(i=null==(i=null==(i=null==e?void 0:e.props)?void 0:i.children)?void 0:i.props)?void 0:i.children)?void 0:i.props)?void 0:i.uri)||(null==(e=null==(i=e[0])?void 0:i.props)?void 0:e.uri):null;g===l&&Spicetify.Platform.History.location.pathname===w&&(a.click(),g=null),(null==(i=v[l])?void 0:i.length)>x&&(x=null==(e=v[l])?void 0:e.length,document.documentElement.style.setProperty("--spicetify-playlist-labels-label-count",""+x));let t=a.querySelector(".spicetify-playlist-labels");h&&t&&(t.remove(),t=null),t||(i=a.querySelector(".main-trackList-rowSectionEnd"),(t=document.createElement("div")).classList.add("spicetify-playlist-labels"),n.default.render(r.default.createElement("div",{className:"spicetify-playlist-labels-labels-container"},null==(e=v[l])?void 0:e.map(e=>{if(!b&&!e.isOwnPlaylist)return null;if(e.isLikedTracks){if("/collection/tracks"===Spicetify.Platform.History.location.pathname)return null}else{var t=e.uri.match(/spotify:playlist:(.*)/)[1];if(Spicetify.Platform.History.location.pathname==="/playlist/"+t)return null}return r.default.createElement(Spicetify.ReactComponent.TooltipWrapper,{label:e.name,placement:"top"},r.default.createElement("div",null,r.default.createElement(Spicetify.ReactComponent.RightClickMenu,{placement:"bottom-end",menu:e.isLikedTracks?null:r.default.createElement(Spicetify.ReactComponent.Menu,null,r.default.createElement(Spicetify.ReactComponent.MenuItem,{leadingIcon:r.default.createElement(Spicetify.ReactComponent.IconComponent,{semanticColor:"textBase",dangerouslySetInnerHTML:{__html:''},iconSize:16}),onClick:t=>{t.stopPropagation(),async function(t,e){await Spicetify.Platform.PlaylistAPI.remove(t,[{uri:e,uid:""}])}(e.uri,l),v[l]=v[l].filter(t=>t.uri!==e.uri),h=!0,P()}},"Remove from ",e.name))},r.default.createElement("div",{className:"spicetify-playlist-labels-label-container",style:{cursor:"pointer"},onClick:t=>{t.stopPropagation();t=e.isLikedTracks?"/collection/tracks":null==(t=Spicetify.URI.fromString(e.uri))?void 0:t.toURLPath(!0);g=l,(w=t)&&Spicetify.Platform.History.push({pathname:t,search:"?uid="+e.trackUid})}},r.default.createElement("img",{src:e.image})))))})),t),i.insertBefore(t,i.firstChild))}h=!1}}async function E(){a=l,(l=document.querySelector("main"))&&!l.isEqualNode(a)&&(a&&d.disconnect(),P(),d.observe(l,{childList:!0,subtree:!0}))}(async()=>{var t;document.getElementById("spicetifyDplaylistDlabels")||((t=document.createElement("style")).id="spicetifyDplaylistDlabels",t.textContent=String.raw` :root{--spicetify-playlist-labels-size:28px;--spicetify-playlist-labels-gap:6px;--spicetify-playlist-labels-container-width:calc(var(--spicetify-playlist-labels-size) * var(--spicetify-playlist-labels-label-count, 3) + var(--spicetify-playlist-labels-gap) * calc(var(--spicetify-playlist-labels-label-count, 3) - 1))}.spicetify-playlist-labels-labels-container{width:var(--spicetify-playlist-labels-container-width);height:var(--row-height);align-items:center;display:flex;overflow:hidden;gap:var(--spicetify-playlist-labels-gap);justify-content:flex-end}.spicetify-playlist-labels-label-container{position:relative;height:calc(var(--row-height) * .5)}.spicetify-playlist-labels-label-container>img{width:calc(var(--row-height) * .5);height:100%;-o-object-fit:cover;object-fit:cover;border-radius:calc(var(--row-height) * .5 * .1)}.main-trackList-trackList.main-trackList-indexable[aria-colcount="4"] .main-trackList-trackListRowGrid{grid-template-columns:[index] var(--tracklist-index-column-width,16px) [first] minmax(120px,var(--col1,4fr)) [var1] minmax(120px,var(--col2,2fr)) [last] calc(120px + var(--spicetify-playlist-labels-container-width) + 12px)!important}.main-trackList-trackList.main-trackList-indexable[aria-colcount="5"] .main-trackList-trackListRowGrid{grid-template-columns:[index] var(--tracklist-index-column-width,16px) [first] minmax(120px,var(--col1,6fr)) [var1] minmax(120px,var(--col2,4fr)) [var2] minmax(120px,var(--col3,3fr)) [last] calc(120px + var(--spicetify-playlist-labels-container-width) + 12px)!important}.main-trackList-trackList.main-trackList-indexable[aria-colcount="6"] .main-trackList-trackListRowGrid{grid-template-columns:[index] var(--tracklist-index-column-width,16px) [first] minmax(120px,var(--col1,6fr)) [var1] minmax(120px,var(--col2,4fr)) [var2] minmax(120px,var(--col3,3fr)) [var3] minmax(120px,var(--col4,2fr)) [last] calc(120px + var(--spicetify-playlist-labels-container-width) + 12px)!important} `.trim(),document.head.appendChild(t))})()}(); \ No newline at end of file diff --git a/src/playlist.tsx b/src/playlist.tsx index 47c3d9d..8293341 100644 --- a/src/playlist.tsx +++ b/src/playlist.tsx @@ -2,45 +2,55 @@ import { getContents, getLikedTracks, getPlaylistItems } from "./api"; export function getAllPlaylists(contents) { let playlists = []; + let ratedPlaylists = []; - function traverse(item) { + function traverse(item, isRated) { if (item.type === 'playlist') { - playlists.push(item); + if (isRated) + ratedPlaylists.push(item); + else + playlists.push(item); } else if (item.type === 'folder' && item.items) { - item.items.forEach(i => traverse(i)); + item.items.forEach(i => traverse(i, item.name == 'Rated')); } } - traverse(contents); + traverse(contents, false); - return playlists; + return [playlists, ratedPlaylists]; } export async function getTrackUriToPlaylistData() { const contents = await getContents(); - const playlists = getAllPlaylists(contents); - const playlistItems = await Promise.all(playlists.map((playlist) => getPlaylistItems(playlist.uri))); + const [playlists, ratedPlaylists] = getAllPlaylists(contents); + const allPlaylistItems = await Promise.all([...playlists, ...ratedPlaylists].map((playlist) => getPlaylistItems(playlist.uri))); + const playlistItems = allPlaylistItems.slice(0, playlists.length); + const ratedPlaylistItems = allPlaylistItems.slice(playlists.length) const trackUriToPlaylistData = {}; const likedTracks = await getLikedTracks(); - playlistItems.forEach((playlistItems, index) => { - playlistItems.forEach((playlistItem) => { - const trackUri = playlistItem.uri; - if (!trackUriToPlaylistData[trackUri]) { - trackUriToPlaylistData[trackUri] = []; - } - if (!trackUriToPlaylistData[trackUri].some(obj => obj.uri === playlists[index].uri)) { - trackUriToPlaylistData[trackUri].push({ - uri: playlists[index].uri, - name: playlists[index].name, - trackUid: playlistItem.uid, - image: playlists[index].images[0]?.url || '', - isOwnPlaylist: playlists[index].isOwnedBySelf, - isLikedTracks: false - }); - } + function addPlaylists(playlists, playlistItems) { + playlistItems.forEach((playlistItems, index) => { + playlistItems.forEach((playlistItem) => { + const trackUri = playlistItem.uri; + if (!trackUriToPlaylistData[trackUri]) { + trackUriToPlaylistData[trackUri] = []; + } + if (!trackUriToPlaylistData[trackUri].some(obj => obj.uri === playlists[index].uri)) { + trackUriToPlaylistData[trackUri].push({ + uri: playlists[index].uri, + name: playlists[index].name, + trackUid: playlistItem.uid, + image: playlists[index].images[0]?.url || '', + isOwnPlaylist: playlists[index].isOwnedBySelf, + isLikedTracks: false + }); + } + }); }); - }); + } + + addPlaylists(playlists, playlistItems); likedTracks.items.forEach((item) => { const trackUri = item.uri; @@ -59,5 +69,7 @@ export async function getTrackUriToPlaylistData() { } }); + addPlaylists(ratedPlaylists, ratedPlaylistItems); + return trackUriToPlaylistData; } \ No newline at end of file