feat: import artist metadata
This commit is contained in:
parent
1368b738ae
commit
96bff400e8
4 changed files with 235 additions and 12 deletions
186
workers/artist-import/index.js
Normal file
186
workers/artist-import/index.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
import slugify from "slugify";
|
||||
import countries from "i18n-iso-countries";
|
||||
|
||||
countries.registerLocale(require("i18n-iso-countries/langs/en.json"));
|
||||
|
||||
function sanitizeMediaString(str) {
|
||||
const sanitizedString = str
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f\u2010\-\.\?\(\)\[\]\{\}]/g, "")
|
||||
.replace(/\.{3}/g, "");
|
||||
return slugify(sanitizedString, {
|
||||
replacement: "-",
|
||||
remove: /[#,&,+()$~%.'\":*?<>{}]/g,
|
||||
lower: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const directusUrl = env["DIRECTUS_URL"];
|
||||
const directusToken = env["DIRECTUS_API_TOKEN"];
|
||||
const artistImportToken = env["ARTIST_IMPORT_TOKEN"];
|
||||
const artistFlowID = env["ARTIST_FLOW_ID"];
|
||||
const albumFlowID = env["ALBUM_FLOW_ID"];
|
||||
const placeholderImageId = "4cef75db-831f-4f5d-9333-79eaa5bb55ee";
|
||||
const requestUrl = new URL(request["url"]);
|
||||
const providedToken = requestUrl.searchParams.get("token");
|
||||
|
||||
if (!providedToken || providedToken !== artistImportToken) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
async function saveToDirectus(endpoint, payload) {
|
||||
const response = await fetch(`${directusUrl}/items/${endpoint}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${directusToken}`,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
data["errors"]
|
||||
? data["errors"][0]["message"]
|
||||
: "Failed to save to Directus"
|
||||
);
|
||||
}
|
||||
return data["data"];
|
||||
}
|
||||
|
||||
async function findGenreIdByName(genreName) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${directusUrl}/items/genres?filter[name][_eq]=${encodeURIComponent(
|
||||
genreName.toLowerCase()
|
||||
)}`,
|
||||
{ headers: { Authorization: `Bearer ${directusToken}` } }
|
||||
);
|
||||
const data = await response.json();
|
||||
return data["data"].length > 0 ? data["data"][0]["id"] : null;
|
||||
} catch (error) {
|
||||
console.error("Error fetching genre ID:", error["message"]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const artistId = requestUrl.searchParams.get("artist_id");
|
||||
if (!artistId)
|
||||
return new Response("artist_id parameter is required", { status: 400 });
|
||||
|
||||
let artistData;
|
||||
try {
|
||||
const artistResponse = await fetch(
|
||||
`${directusUrl}/flows/trigger/${artistFlowID}?artist_id=${artistId}&import_token=${artistImportToken}`,
|
||||
{ headers: { Authorization: `Bearer ${directusToken}` } }
|
||||
);
|
||||
artistData = await artistResponse.json();
|
||||
artistData =
|
||||
artistData["get_artist_data"]["data"]["MediaContainer"]["Metadata"][0];
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Error fetching artist data from Directus flow:",
|
||||
error["message"]
|
||||
);
|
||||
return new Response("Error fetching artist data", { status: 500 });
|
||||
}
|
||||
|
||||
const artistName = artistData["title"] || "";
|
||||
const artistKey = sanitizeMediaString(artistName);
|
||||
const countryName = artistData["Country"]
|
||||
? artistData["Country"][0]?.["tag"]
|
||||
: "";
|
||||
const countryIsoCode = countries.getAlpha2Code(countryName, "en") || "";
|
||||
const slug = `/music/artists/${artistKey}-${countryName.toLowerCase()}`;
|
||||
const description = artistData["summary"] || "";
|
||||
const mbid = artistData["Guid"]?.[0]?.["id"]?.replace("mbid://", "") || "";
|
||||
|
||||
const genreNames = artistData["Genre"]
|
||||
? artistData["Genre"].map((g) => g["tag"].toLowerCase())
|
||||
: [];
|
||||
let genreId = null;
|
||||
for (const genreName of genreNames) {
|
||||
genreId = await findGenreIdByName(genreName);
|
||||
if (genreId) break;
|
||||
}
|
||||
|
||||
const artistPayload = {
|
||||
name: artistName,
|
||||
name_string: artistName,
|
||||
slug: slug,
|
||||
description: description,
|
||||
mbid: mbid,
|
||||
tentative: true,
|
||||
genres: genreId,
|
||||
country: countryIsoCode,
|
||||
art: placeholderImageId,
|
||||
};
|
||||
|
||||
let insertedArtist;
|
||||
try {
|
||||
insertedArtist = await saveToDirectus("artists", artistPayload);
|
||||
} catch (error) {
|
||||
console.error("Error saving artist:", error["message"]);
|
||||
return new Response("Error saving artist", { status: 500 });
|
||||
}
|
||||
|
||||
let albumData;
|
||||
try {
|
||||
const albumResponse = await fetch(
|
||||
`${directusUrl}/flows/trigger/${albumFlowID}?artist_id=${artistId}&import_token=${artistImportToken}`,
|
||||
{ headers: { Authorization: `Bearer ${directusToken}` } }
|
||||
);
|
||||
albumData = await albumResponse.json();
|
||||
albumData =
|
||||
albumData["get_album_data"]["data"]["MediaContainer"]["Metadata"];
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Error fetching album data from Directus flow:",
|
||||
error["message"]
|
||||
);
|
||||
return new Response("Error fetching album data", { status: 500 });
|
||||
}
|
||||
|
||||
for (const album of albumData) {
|
||||
const albumName = album["title"] || "";
|
||||
const albumKey = `${artistKey}-${sanitizeMediaString(albumName)}`;
|
||||
const albumSlug = `/music/albums/${albumKey}`;
|
||||
const albumDescription = album["summary"] || "";
|
||||
const albumReleaseDate = album["originallyAvailableAt"] || "";
|
||||
const albumReleaseYear = albumReleaseDate
|
||||
? new Date(albumReleaseDate).getFullYear()
|
||||
: null;
|
||||
const albumGenres = album["Genre"]
|
||||
? album["Genre"].map((g) => g["tag"])
|
||||
: [];
|
||||
const albumMbid =
|
||||
album["Guid"]?.[0]?.["id"]?.replace("mbid://", "") || null;
|
||||
|
||||
const albumPayload = {
|
||||
name: albumName,
|
||||
key: albumKey,
|
||||
slug: albumSlug,
|
||||
mbid: albumMbid,
|
||||
description: albumDescription,
|
||||
release_year: albumReleaseYear,
|
||||
artist: insertedArtist["id"],
|
||||
artist_name: artistName,
|
||||
genres: albumGenres,
|
||||
art: placeholderImageId,
|
||||
tentative: true,
|
||||
};
|
||||
|
||||
try {
|
||||
await saveToDirectus("albums", albumPayload);
|
||||
} catch (error) {
|
||||
console.error("Error saving album:", error["message"]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response("Artist and albums synced successfully", {
|
||||
status: 200,
|
||||
});
|
||||
},
|
||||
};
|
15
workers/artist-import/wrangler.template.toml
Normal file
15
workers/artist-import/wrangler.template.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
name = "import-artist-worker"
|
||||
main = "./index.js"
|
||||
compatibility_date = "2023-01-01"
|
||||
|
||||
account_id = "${CF_ACCOUNT_ID}"
|
||||
workers_dev = true
|
||||
|
||||
[observability]
|
||||
enabled = true
|
||||
|
||||
[env.production]
|
||||
name = "import-artist-worker-production"
|
||||
routes = [
|
||||
{ pattern = "coryd.dev/api/import-artist*", zone_id = "${CF_ZONE_ID}" }
|
||||
]
|
Reference in a new issue