Skip to content

Commit

Permalink
MediaItemCache - Enforce item type to avoid invalid page navigation w…
Browse files Browse the repository at this point in the history
…hen populating cache
  • Loading branch information
Inrixia committed Jan 30, 2025
1 parent 934e71c commit a6ad86e
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 25 deletions.
4 changes: 2 additions & 2 deletions plugins/CoverTheme/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async function updateBackground(productId: string) {
if (prevSong === productId) return;
prevSong = productId;

const mediaItem = await MediaItemCache.ensure(productId);
const mediaItem = await MediaItemCache.ensureTrack(productId);
if (!mediaItem || !mediaItem.album?.cover) return;

if (prevCover === mediaItem.album.cover) return;
Expand Down Expand Up @@ -56,7 +56,7 @@ const unloadTransition = intercept("playbackControls/MEDIA_PRODUCT_TRANSITION",
// @ts-expect-error - Neptune doesn't type this action
const unloadPreload = intercept("player/PRELOAD_ITEM", async ([item]: any[]) => {
if (item.productType !== "track") return;
const mediaItem = await MediaItemCache.ensure(item.productId);
const mediaItem = await MediaItemCache.ensureTrack(item.productId);
if (!mediaItem || !mediaItem.album?.cover) return;
getPaletteCached(mediaItem.album.cover);
});
Expand Down
4 changes: 2 additions & 2 deletions plugins/DiscordRPC/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const setRPC = (activity?: SetActivity) => setActivity(activity).catch(trace.err

const unloadTransition = intercept("playbackControls/MEDIA_PRODUCT_TRANSITION", ([media]) => {
const mediaProduct = media.mediaProduct as { productId: string };
MediaItemCache.ensure(mediaProduct.productId)
MediaItemCache.ensureTrack(mediaProduct.productId)
.then((track) => {
if (track) update({ track, time: 0 });
})
Expand All @@ -97,7 +97,7 @@ const unloadPause = intercept("playbackControls/PAUSE", () => {
const { playbackContext, playbackState, latestCurrentTime } = getPlaybackControl();

update({
track: await MediaItemCache.ensure(playbackContext?.actualProductId),
track: await MediaItemCache.ensureTrack(playbackContext?.actualProductId),
time: latestCurrentTime,
paused: playbackState !== "PLAYING",
});
Expand Down
2 changes: 1 addition & 1 deletion plugins/RealMAX/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
);
if (maxItem === false || maxItem === undefined) continue;
if (maxItem?.id !== undefined) {
if ((await MediaItemCache.ensure(trackId)) !== undefined) {
if ((await MediaItemCache.ensureTrack(trackId)) !== undefined) {
trace.msg.log(`Found Max quality for ${maxItem.title} in ${sourceName}! ${index}/${trackItems.length - 1} done.`);
trackIds.push(+maxItem.id);
maxIdsFound++;
Expand Down
2 changes: 1 addition & 1 deletion plugins/SongDownloader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const downloadTrack = async (trackItem: TrackItem, updateMethods: ButtonMethods,

updateMethods.set("Fetching playback info & tags...");
const playbackInfo = PlaybackInfoCache.ensure(trackId, settings.desiredDownloadQuality);
const metaTags = makeTags((await ExtendedMediaItem.get(trackId))!);
const metaTags = makeTags((await ExtendedMediaItem.getTrack(trackId))!);
const pathInfo = parseFileName(await metaTags, await playbackInfo);

pathInfo.basePath = folderPath;
Expand Down
13 changes: 10 additions & 3 deletions plugins/_lib/Caches/ExtendedTrackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ export class ExtendedMediaItem {
public static current(playbackContext?: PlaybackContext) {
playbackContext ??= getPlaybackControl()?.playbackContext;
if (playbackContext?.actualProductId === undefined) return undefined;
return this.get(playbackContext.actualProductId);
return this.get(playbackContext.actualProductId, playbackContext.actualVideoQuality !== null);
}

public static async get(itemId?: ItemId) {
public static getVideo(itemId?: ItemId) {
if (itemId === undefined) return undefined;
const trackItem = await MediaItemCache.ensure(itemId);
return this.get(itemId, true);
}
public static getTrack(itemId?: ItemId) {
if (itemId === undefined) return undefined;
return this.get(itemId, false);
}
private static async get(itemId: ItemId, isVideo: boolean) {
const trackItem = await MediaItemCache.ensure(itemId, isVideo);
if (trackItem === undefined) return undefined;
this._ExtendedMediaItems[itemId] ??= new this(itemId, trackItem);
return this._ExtendedMediaItems[itemId];
Expand Down
23 changes: 9 additions & 14 deletions plugins/_lib/Caches/MediaItemCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,27 @@ import getPlaybackControl from "../getPlaybackControl";

import { libTrace } from "../trace";

let currentPage: string | null = null;

export type MediaItem = TrackItem | VideoItem;
export class MediaItemCache {
private static readonly _cache: Record<ItemId, MediaItem> = {};
public static current(playbackContext?: PlaybackContext) {
playbackContext ??= getPlaybackControl()?.playbackContext;
if (playbackContext?.actualProductId === undefined) return undefined;
return this.ensure(playbackContext.actualProductId);
return this.ensure(playbackContext.actualProductId, playbackContext.actualVideoQuality !== null);
}
public static async ensureTrack(itemId?: ItemId) {
const mediaItem = await this.ensure(itemId);
if (itemId === undefined) return undefined;
const mediaItem = await this.ensure(itemId, false);
if (mediaItem?.contentType === "track") return mediaItem;
return undefined;
}
public static async ensureVideo(itemId?: ItemId) {
const mediaItem = await this.ensure(itemId);
if (itemId === undefined) return undefined;
const mediaItem = await this.ensure(itemId, true);
if (mediaItem?.contentType === "video") return mediaItem;
return undefined;
}
public static async ensure(itemId?: ItemId) {
if (itemId === undefined) return undefined;

public static async ensure(itemId: ItemId, isVideo: boolean) {
let mediaItem = this._cache[itemId];
if (mediaItem !== undefined) return mediaItem;

Expand All @@ -39,12 +37,12 @@ export class MediaItemCache {
}

if (this._cache[itemId] === undefined) {
if (currentPage === null) currentPage = window.location.pathname;
const currentPage = window.location.pathname;
const loadedTrack = await interceptPromise(() => neptune.actions.router.replace(<any>`/track/${itemId}`), ["page/IS_DONE_LOADING"], [])
.then(() => true)
.catch(libTrace.warn.withContext(`TrackItemCache.ensure failed to load track ${itemId}`));
// If we fail to load the track, maybe its a video, try that instead as a last ditch attempt
if (!loadedTrack) {
if (!loadedTrack && isVideo) {
await interceptPromise(() => neptune.actions.router.replace(<any>`/video/${itemId}`), ["page/IS_DONE_LOADING"], []).catch(
libTrace.warn.withContext(`TrackItemCache.ensure failed to load video ${itemId}`)
);
Expand All @@ -54,10 +52,7 @@ export class MediaItemCache {
const trackItem = mediaItems[+itemId]?.item;
this._cache[itemId] = trackItem;

setTimeout(() => {
currentPage = null;
neptune.actions.router.replace(<any>currentPage);
});
setTimeout(() => neptune.actions.router.replace(<any>currentPage));
}

return this._cache[itemId];
Expand Down
4 changes: 2 additions & 2 deletions plugins/_lib/MaxTrack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ItemId, MediaItem, TrackItem } from "neptune-types/tidal";
export type TrackFilter = (trackItem: TApiTrack) => boolean;
export class MaxTrack {
public static getMaxTrack = AsyncCachable(async (itemId: ItemId): Promise<TrackItem | false> => {
const extTrackItem = await ExtendedMediaItem.get(itemId);
const extTrackItem = await ExtendedMediaItem.getTrack(itemId);
if (extTrackItem === undefined) return false;
if (extTrackItem.tidalTrack.contentType === "track" && this.hasHiRes(extTrackItem.tidalTrack)) return false;

Expand All @@ -17,7 +17,7 @@ export class MaxTrack {
return false;
});
public static getLatestMaxTrack = AsyncCachable(async (itemId: ItemId): Promise<TrackItem | false> => {
const extTrackItem = await ExtendedMediaItem.get(itemId);
const extTrackItem = await ExtendedMediaItem.getTrack(itemId);
if (extTrackItem === undefined) return false;

let currentTrackItem: TrackItem | false = false;
Expand Down

0 comments on commit a6ad86e

Please sign in to comment.