Skip to content

Commit

Permalink
Implement #97 RealMAX.settings.considerNewestRelease
Browse files Browse the repository at this point in the history
  • Loading branch information
Inrixia committed Nov 6, 2024
1 parent 4f2ded2 commit ef42362
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 38 deletions.
2 changes: 2 additions & 0 deletions plugins/RealMAX/src/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SwitchSetting } from "@inrixia/lib/components/SwitchSetting";
export const settings = getSettings({
displayMaxContextButton: true,
displayInfoPopups: true,
considerNewestRelease: false,
});

export const Settings = () => html`<div>
Expand All @@ -14,4 +15,5 @@ export const Settings = () => html`<div>
title="Display RealMAX Button on Context Menu's"
/>
<${SwitchSetting} checked=${settings.displayInfoPopups} onClick=${() => (settings.displayInfoPopups = !settings.displayInfoPopups)} title="Display RealMAX queue event popups" />
<${SwitchSetting} checked=${settings.considerNewestRelease} onClick=${() => (settings.considerNewestRelease = !settings.considerNewestRelease)} title="Also consider newest release for playlists" />
</div>`;
8 changes: 6 additions & 2 deletions plugins/RealMAX/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
for (const index in trackItems) {
const trackItem = trackItems[index];
const trackId = trackItem.id!;
const maxItem = await MaxTrack.getMaxTrack(trackItem.id).catch(trace.msg.err.withContext(`Failed to create ${sourceName}`));
if (maxItem !== false && maxItem?.id !== undefined) {
if (trackId === undefined) continue;
const maxItem = await MaxTrack[settings.considerNewestRelease ? "getLatestMaxTrack" : "getMaxTrack"](trackId).catch(
trace.msg.err.withContext(`Skipping adding ${trackItem.title} to ${sourceName}`)
);
if (maxItem === false || maxItem === undefined) continue;
if (maxItem?.id !== undefined) {
if ((await MediaItemCache.ensure(trackId)) !== undefined) {
trace.msg.log(`Found Max quality for ${maxItem.title} in ${sourceName}! ${index}/${trackItems.length - 1} done.`);
trackIds.push(+maxItem.id);
Expand Down
5 changes: 3 additions & 2 deletions plugins/Shazam/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@ const handleDrop = async (event: DragEvent) => {
if (matches.length === 0) return trace.msg.warn(`No matches for ${file.name}`);
for (const shazamData of matches) {
const trackName = shazamData.track?.share?.text ?? `${shazamData.track?.title ?? "unknown"} by ${shazamData.track?.artists?.[0] ?? "unknown"}"`;
const prefix = `[File: ${file.name}, Match: "${trackName}]`;
const prefix = `[File: ${file.name}, Match: ${trackName}]`;
const isrc = shazamData.track?.isrc;
trace.log(shazamData);
if (isrc === undefined) {
trace.msg.log(`${prefix} No isrc returned from Shazam cannot add to playlist.`);
continue;
}
let trackToAdd;
for await (trackToAdd of MaxTrack.getMaxTrackFromISRC(isrc)) {
for await (trackToAdd of MaxTrack.getTracksFromISRC(isrc)) {
// Break on first HiRes track. Otherwise trackToAdd will just be the final track found.
if (MaxTrack.hasHiRes(trackToAdd)) break;
}
if (trackToAdd !== undefined) {
Expand Down
7 changes: 7 additions & 0 deletions plugins/_lib/Caches/AsyncCachable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const AsyncCachable = <K extends string | number | symbol, V>(generator: (key: K) => Promise<V>) => {
const _cache: Record<K, Promise<V>> = <any>{};
return (key: K): Promise<V> => {
if (key in _cache) return _cache[key];
return (_cache[key] = generator(key));
};
};
9 changes: 0 additions & 9 deletions plugins/_lib/Caches/ExtendedTrackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,4 @@ export class ExtendedMediaItem {
}
return this._releaseTrack;
}

public async everything() {
return {
tidalTrack: this.tidalTrack,
tidalAlbum: await this.tidalAlbum(),
releaseTrack: await this.releaseTrack(),
releaseAlbum: await this.releaseAlbum(),
};
}
}
66 changes: 42 additions & 24 deletions plugins/_lib/MaxTrack.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,56 @@
import { fetchIsrcIterable, Resource } from "./api/tidal";
import { AsyncCachable } from "./Caches/AsyncCachable";
import { ExtendedMediaItem } from "./Caches/ExtendedTrackItem";
import { MediaItemCache } from "./Caches/MediaItemCache";
import { ItemId, TrackItem } from "neptune-types/tidal";

export type TrackFilter = (trackItem: Resource) => boolean;
export class MaxTrack {
private static readonly _maxTrackMap: Record<ItemId, Promise<TrackItem | false>> = {};
public static async fastCacheMaxId(itemId: ItemId): Promise<TrackItem | false> {
if (itemId === undefined) return false;
return MaxTrack._maxTrackMap[itemId];
}
public static async getMaxTrack(itemId: ItemId | undefined): Promise<TrackItem | false> {
if (itemId === undefined) return false;

const maxTrack = MaxTrack._maxTrackMap[itemId];
if (maxTrack !== undefined) return maxTrack;

public static getMaxTrack = AsyncCachable(async (itemId: ItemId): Promise<TrackItem | false> => {
for await (const trackItem of this.getTracksFromItemId(itemId, this.hasHiRes)) {
return trackItem;
}
return false;
});
public static getLatestMaxTrack = AsyncCachable(async (itemId: ItemId): Promise<TrackItem | false> => {
let currentTrackItem: TrackItem | false = false;
for await (const trackItem of this.getTracksFromItemId(itemId)) {
if (currentTrackItem === undefined) {
currentTrackItem = trackItem;
continue;
}
const isLowerQuality = !this.hasHiRes(trackItem) && this.hasHiRes(<TrackItem>currentTrackItem);
const isHigherQuality = this.hasHiRes(trackItem) && !this.hasHiRes(<TrackItem>currentTrackItem);
if (isLowerQuality) continue;
if (isHigherQuality) {
currentTrackItem = trackItem;
continue;
}
const isNewer = new Date(trackItem.streamStartDate!) > new Date((<TrackItem>currentTrackItem).streamStartDate!);
if (isNewer) {
currentTrackItem = trackItem;
continue;
}
}
return currentTrackItem;
});
public static async *getTracksFromItemId(itemId: ItemId, filter?: TrackFilter): AsyncGenerator<TrackItem> {
const extTrackItem = await ExtendedMediaItem.get(itemId);
if (extTrackItem === undefined) return false;
const trackItem = extTrackItem?.tidalTrack;
if (trackItem.contentType !== "track" || this.hasHiRes(trackItem)) return false;
if (extTrackItem === undefined) return;

const { tidalTrack } = extTrackItem;
if (tidalTrack.contentType !== "track") return;

const isrcs = await extTrackItem.isrcs();
if (isrcs.size === 0) return (this._maxTrackMap[itemId] = Promise.resolve(false));
if (isrcs.size === 0) return;

return (this._maxTrackMap[itemId] = (async () => {
for (const isrc of isrcs) {
for await (const trackItem of this.getMaxTrackFromISRC(isrc, this.hasHiRes)) {
return trackItem;
}
for (const isrc of isrcs) {
for await (const trackItem of this.getTracksFromISRC(isrc, filter)) {
yield trackItem;
}
return false;
})());
}
}
public static async *getMaxTrackFromISRC(isrc: string, filter?: (trackItem: Resource) => boolean): AsyncGenerator<TrackItem> {
public static async *getTracksFromISRC(isrc: string, filter?: TrackFilter): AsyncGenerator<TrackItem> {
for await (const { resource } of fetchIsrcIterable(isrc)) {
if (resource?.id === undefined) continue;
if (resource.artifactType !== "track") continue;
Expand All @@ -44,6 +62,6 @@ export class MaxTrack {
public static hasHiRes(trackItem: Resource | TrackItem): boolean {
const tags = trackItem.mediaMetadata?.tags;
if (tags === undefined) return false;
return tags.findIndex((tag) => tag === "HIRES_LOSSLESS") !== -1;
return tags.includes("HIRES_LOSSLESS");
}
}
3 changes: 2 additions & 1 deletion plugins/_lib/makeTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ export const makeTags = async (extTrackItem: ExtendedMediaItem): Promise<MetaTag
)
.catch(() => undefined)
.then((res) => res?.[0]);
const { tidalTrack, releaseAlbum, releaseTrack, tidalAlbum } = await extTrackItem.everything();
const [tidalAlbum, releaseTrack, releaseAlbum] = await Promise.all([extTrackItem.tidalAlbum(), extTrackItem.releaseTrack(), extTrackItem.releaseAlbum()]);
const tidalTrack = extTrackItem.tidalTrack;

const tags: FlacTags = {};
if (tidalTrack.title !== undefined) tags.title = fullTitle(tidalTrack, releaseTrack);
Expand Down

0 comments on commit ef42362

Please sign in to comment.