Skip to content

Commit

Permalink
Shazam - Update to work with latest Neptune, fixes #95
Browse files Browse the repository at this point in the history
  • Loading branch information
Inrixia committed Oct 29, 2024
1 parent ea07892 commit 2d85bdd
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 59 deletions.
6 changes: 3 additions & 3 deletions plugins/Shazam/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"author": "Inrixia",
"main": "./src/index.js",
"dependencies": {
"@inrixia/lib": "workspace:*",
"shazamio-core": "^1.3.1",
"uuid": "^10.0.0",
"@inrixia/lib": "workspace:*"
"uuid": "^10.0.0"
},
"scripts": {
"postinstall": "node ./fixShazamio.js"
},
"devDependencies": {
"@types/uuid": "^9.0.8"
}
}
}
File renamed without changes.
63 changes: 24 additions & 39 deletions plugins/Shazam/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import type * as shazamio from "shazamio-core/web";
const { default: init, recognizeBytes } = <typeof shazamio>require("shazamio-core/web");
init();

import { actions, store } from "@neptune";
import { DecodedSignature } from "shazamio-core";
import { interceptPromise } from "@inrixia/lib/intercept/interceptPromise";
import { fetchShazamData } from "./shazamApi/fetch";

import { fetchIsrc } from "@inrixia/lib/api/tidal";

import { Tracer } from "@inrixia/lib/trace";
const trace = Tracer("[Shazam]");

import { settings } from "./Settings";
import { recognizeTrack } from "./shazam.native";
export { Settings } from "./Settings";

const addToPlaylist = async (playlistUUID: string, mediaItemIdsToAdd: string[]) => {
Expand All @@ -25,12 +20,6 @@ const addToPlaylist = async (playlistUUID: string, mediaItemIdsToAdd: string[])
setTimeout(() => actions.content.loadListItemsPage({ listName: `playlists/${playlistUUID}`, listType: "mediaItems", reset: true }), 1000);
};

export const using = async <T>(signatures: DecodedSignature[], fun: (signatures: ReadonlyArray<DecodedSignature>) => T) => {
const ret = await fun(signatures);
for (const signature of signatures) signature.free();
return ret;
};

// Define the function
const handleDrop = async (event: DragEvent) => {
event.preventDefault();
Expand All @@ -40,40 +29,36 @@ const handleDrop = async (event: DragEvent) => {
const { pathname, params } = store.getState().router;

if (!pathname.startsWith("/playlist/")) {
return trace.err(`This is not a playlist!`);
return trace.msg.err(`This is not a playlist!`);
}
const playlistUUID: string = params.id;
for (const file of event.dataTransfer?.files ?? []) {
const bytes = await file.arrayBuffer();
if (bytes === undefined) continue;

trace.log(`Matching ${file.name}...`);
try {
await using(recognizeBytes(new Uint8Array(bytes), 0, Number.MAX_SAFE_INTEGER), async (signatures) => {
let i = settings.startInMiddle ? Math.floor(signatures.length / 2) : 1;
for (; i < signatures.length; i += 4) {
trace.log(`Matching ${file.name}...`);
const sig = signatures[i];
const shazamData = await fetchShazamData({ samplems: sig.samplems, uri: sig.uri });
if (shazamData.matches.length === 0) continue;

const trackName = shazamData.track?.share?.subject ?? "Unknown";
const isrc = shazamData.track?.isrc;
const isrcData = isrc !== undefined ? await fetchIsrc(isrc).catch(() => undefined) : undefined;
const ids = (isrcData?.data ?? []).map((track) => track.id);
if (ids.length > 0) {
trace.log(`Adding ${trackName} to playlist`);
await addToPlaylist(
playlistUUID,
ids.filter((id) => id !== undefined)
);
} else {
trace.log(shazamData);
trace.msg.log(`Track ${trackName} is not avalible in Tidal`);
}
if (settings.exitOnFirstMatch) return;
}
trace.msg.warn(`No matches for ${file.name}`);
const matches = await recognizeTrack({
bytes,
startInMiddle: settings.startInMiddle,
exitOnFirstMatch: settings.exitOnFirstMatch,
});
if (matches.length === 0) return trace.msg.warn(`No matches for ${file.name}`);
for (const shazamData of matches) {
const trackName = shazamData.track?.share?.subject ?? "Unknown";
const isrc = shazamData.track?.isrc;
const isrcData = isrc !== undefined ? await fetchIsrc(isrc).catch(() => undefined) : undefined;
const ids = (isrcData?.data ?? []).map((track) => track.id);
if (ids.length > 0) {
trace.msg.log(`Adding ${trackName} to playlist`);
await addToPlaylist(
playlistUUID,
ids.filter((id) => id !== undefined)
);
} else {
trace.log(shazamData);
trace.msg.log(`Track ${trackName} is not avalible in Tidal`);
}
}
} catch (err) {
trace.msg.err.withContext(`Failed to recognize ${file.name}`)(<Error>err);
}
Expand Down
45 changes: 45 additions & 0 deletions plugins/Shazam/src/shazam.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import init from "shazamio-core/web";
import { recognizeBytes, type DecodedSignature } from "shazamio-core/web";
init();

import { v4 } from "uuid";

import { requestJsonCached } from "@inrixia/lib/native/request/requestJsonCached.native";
import type { ShazamData } from "./api.types";

export const using = async <T>(signatures: DecodedSignature[], fun: (signatures: ReadonlyArray<DecodedSignature>) => T) => {
const ret = await fun(signatures);
for (const signature of signatures) signature.free();
return ret;
};

export const fetchShazamData = async (signature: { samplems: number; uri: string }) =>
requestJsonCached<ShazamData>(
`https://amp.shazam.com/discovery/v5/en-US/US/iphone/-/tag/${v4()}/${v4()}?sync=true&webv3=true&sampling=true&connected=&shazamapiversion=v3&sharehub=true&hubv5minorversion=v5.1&hidelb=true&video=v3`,
{
headers: { "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify({ signature }),
}
);

type Opts = {
bytes: ArrayBuffer;
startInMiddle: boolean;
exitOnFirstMatch: boolean;
};

export const recognizeTrack = async ({ bytes, startInMiddle, exitOnFirstMatch }: Opts) => {
const matches: ShazamData[] = [];
await using(recognizeBytes(new Uint8Array(bytes), 0, Number.MAX_SAFE_INTEGER), async (signatures) => {
let i = startInMiddle ? Math.floor(signatures.length / 2) : 1;
for (; i < signatures.length; i += 4) {
const sig = signatures[i];
const shazamData = await fetchShazamData({ samplems: sig.samplems, uri: sig.uri });
matches.push(shazamData);
if (shazamData.matches.length === 0) continue;
if (exitOnFirstMatch) return;
}
});
return matches;
};
13 changes: 0 additions & 13 deletions plugins/Shazam/src/shazamApi/fetch.ts

This file was deleted.

8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2d85bdd

Please sign in to comment.