Skip to content

Commit

Permalink
RealMAX - Add button to Context menus for generating a playlist re #33
Browse files Browse the repository at this point in the history
  • Loading branch information
Inrixia committed Jun 24, 2024
1 parent 67b0016 commit 0c1d58c
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 15 deletions.
15 changes: 15 additions & 0 deletions plugins/RealMAX/src/Settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { $, html } from "@neptune/voby";
import { getSettings } from "@inrixia/lib/storage";
import { SwitchSetting } from "@inrixia/lib/components/SwitchSetting";

export const settings = getSettings({
displayMaxContextButton: true,
});

export const Settings = () => html`<div>
<${SwitchSetting}
checked=${settings.displayMaxContextButton}
onClick=${() => (settings.displayMaxContextButton = !settings.displayMaxContextButton)}
title="Display RealMAX Button on Context Menu's"
/>
</div>`;
66 changes: 58 additions & 8 deletions plugins/RealMAX/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import safeUnload from "@inrixia/lib/safeUnload";
import { interceptPromise } from "@inrixia/lib/intercept/interceptPromise";
import { MaxTrack } from "./MaxTrack";
import { ContextMenu } from "@inrixia/lib/ContextMenu";
import { AlbumCache } from "@inrixia/lib/Caches/AlbumCache";
import { settings } from "./Settings";
const trace = Tracer("[RealMAX]");

export const hasHiRes = (trackItem: TrackItem) => {
Expand All @@ -16,6 +18,8 @@ export const hasHiRes = (trackItem: TrackItem) => {
return tags.findIndex((tag) => tag === "HIRES_LOSSLESS") !== -1;
};

export { Settings } from "./Settings";

const unloadIntercept = intercept(
"playbackControls/MEDIA_PRODUCT_TRANSITION",
debounce(async () => {
Expand All @@ -38,16 +42,62 @@ const unloadIntercept = intercept(
);

ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
if (trackItems.length === 0) return;
document.getElementById("realMax-button")?.remove();
if (trackItems.length === 0 || !settings.displayMaxContextButton) return;

let sourceName = trackItems[0].title;
if (contextSource.type === "PLAYLIST") sourceName = store.getState().content.playlists.find((playlist) => playlist.uuid === contextSource.playlistId)?.title;
else if (contextSource.type === "ALBUM") sourceName = (await AlbumCache.get(+contextSource.albumId))?.title;
sourceName = `${sourceName} - RealMAX`;

const downloadButton = document.createElement("button");
downloadButton.type = "button";
downloadButton.role = "menuitem";
downloadButton.textContent = `RealMAX - Process ${trackItems.length} tracks`;
downloadButton.id = "realMax-button";
downloadButton.className = "context-button"; // Set class name for styling
contextMenu.appendChild(downloadButton);
const maxButton = document.createElement("button");
maxButton.type = "button";
maxButton.role = "menuitem";
maxButton.textContent = `RealMAX - Process ${trackItems.length} tracks`;
maxButton.id = "realMax-button";
maxButton.className = "context-button"; // Set class name for styling
maxButton.addEventListener("click", async () => {
maxButton.remove();
const [{ playlist }] = await interceptPromise(
() =>
actions.folders.createPlaylist({
description: "Automatically generated by RealMAX",
folderId: "root",
fromPlaylist: undefined,
isPublic: false,
title: sourceName,
}),
["content/LOAD_PLAYLIST_SUCCESS"],
["content/LOAD_PLAYLIST_FAIL"]
);
if (playlist?.uuid === undefined) {
return trace.msg.err(`Failed to create playlist "${sourceName}"`);
}
for (const index in trackItems) {
const trackItem = trackItems[index];
let itemId = trackItem.id!;
const maxItem = await MaxTrack.getMaxId(trackItem.id);
if (maxItem !== false && maxItem.id !== undefined) {
trace.msg.log(`Found Max quality for ${maxItem.title}! Adding to playlsit ${sourceName}...`);
itemId = +maxItem.id;
}
await TrackItemCache.ensure(itemId);
await interceptPromise(
() =>
actions.content.addMediaItemsToPlaylist({
addToIndex: +index,
mediaItemIdsToAdd: [itemId],
onArtifactNotFound: "FAIL",
onDupes: "ADD",
playlistUUID: playlist.uuid!,
showNotification: false,
}),
["content/ADD_MEDIA_ITEMS_TO_PLAYLIST_SUCCESS"],
["content/ADD_MEDIA_ITEMS_TO_PLAYLIST_FAIL"]
);
}
});
contextMenu.appendChild(maxButton);
});

export const onUnload = () => {
Expand Down
4 changes: 2 additions & 2 deletions plugins/SongDownloader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ const buttonMethods = (id: string): ButtonMethods => ({
export const onUnload = safeUnload;

ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
if (trackItems.length === 0) return;
document.getElementById("download-button")?.remove();
if (trackItems.length === 0) return;

const downloadButton = document.createElement("button");
downloadButton.type = "button";
Expand All @@ -74,7 +74,6 @@ ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
downloadButton.classList.add("loading");
}
downloadButtons[context] = downloadButton;
contextMenu.appendChild(downloadButton);
const { prep, onProgress, clear } = buttonMethods(context);
downloadButton.addEventListener("click", async () => {
if (context === undefined) return;
Expand All @@ -85,6 +84,7 @@ ContextMenu.onOpen(async (contextSource, contextMenu, trackItems) => {
}
clear();
});
contextMenu.appendChild(downloadButton);
});

export const downloadTrack = async (track: TrackItem, trackOptions: TrackOptions, options?: DownloadTrackOptions) => {
Expand Down
10 changes: 5 additions & 5 deletions plugins/_lib/ContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@ import { libTrace } from "./trace";
import { AlbumCache } from "./Caches/AlbumCache";
import { PlaylistCache } from "./Caches/PlaylistItemCache";

type ContextSource = "ALBUM" | "PLAYLIST" | "TRACK";
type ContextSource = { type: "TRACK" } | { type: "ALBUM"; albumId: ItemId } | { type: "PLAYLIST"; playlistId: ItemId };
type ContextListener = (contextSource: ContextSource, contextMenu: Element, trackItems: TrackItem[]) => Promise<void>;
export class ContextMenu {
private static readonly _albumsCache: Record<string, Promise<TrackItem[]> | undefined> = {};
private static readonly _playlistsCache: Record<ItemId, Promise<TrackItem[]> | undefined> = {};
private static readonly _intercepts = [
intercept([`contextMenu/OPEN_MEDIA_ITEM`], ([mediaItem]) => {
(async () => {
this._onOpen("TRACK", await this.getTrackItems([mediaItem.id]));
this._onOpen({ type: "TRACK" }, await this.getTrackItems([mediaItem.id]));
})();
}),
intercept([`contextMenu/OPEN_MULTI_MEDIA_ITEM`], ([mediaItems]) => {
(async () => {
this._onOpen("TRACK", await this.getTrackItems(mediaItems.ids));
this._onOpen({ type: "TRACK" }, await this.getTrackItems(mediaItems.ids));
})();
}),
intercept("contextMenu/OPEN", ([info]) => {
switch (info.type) {
case "ALBUM": {
AlbumCache.getTrackItems(info.id).then((trackItems) => {
if (trackItems !== undefined) this._onOpen("ALBUM", trackItems);
if (trackItems !== undefined) this._onOpen({ type: "ALBUM", albumId: info.id }, trackItems);
});
break;
}
case "PLAYLIST": {
PlaylistCache.getTrackItems(info.id).then((trackItems) => {
if (trackItems !== undefined) this._onOpen("PLAYLIST", trackItems);
if (trackItems !== undefined) this._onOpen({ type: "PLAYLIST", playlistId: info.id }, trackItems);
});
break;
}
Expand Down

0 comments on commit 0c1d58c

Please sign in to comment.