Create exporter.js

This commit is contained in:
Holly Stubbs 2024-04-10 17:00:37 +01:00
parent 5c4fff5abc
commit 1174281ed9

133
exporter.js Normal file
View file

@ -0,0 +1,133 @@
#!/bin/node
// Add your details here
const SERVER_ADDRESS = "https://jellyfin.example.com"; // Don't leave a trailing slash!!!
const API_KEY = ""; // Get this from Administration > API Keys
const USER_NAME = "user";
const LIBRARY_NAME = "Music";
if (SERVER_ADDRESS.includes("example") || API_KEY.trim() === "" || USER_NAME.trim() === "" || LIBRARY_NAME.trim() === "") {
console.log("Details are invalid, check the details at the top of this script file! (Lines 3 - 7)");
return;
}
const fs = require("fs");
let outText = "";
let albumCount = 0;
let songCount = 0;
class StrippedFunkyArray {
constructor() {
this.items = {};
this.itemKeys = [];
this.undefIndex = 9999;
}
set(key, item, regenerate = true) {
this.items[key] = item;
if (regenerate) {
this.itemKeys = Object.keys(this.items);
}
return item;
}
get(key) {
return this.items[key];
}
}
async function apiRequest(url) {
const res = await fetch(`${SERVER_ADDRESS}/${url}`, {
headers: {
Authorization: `Mediabrowser Token="${API_KEY}"`
}
});
return await res.json();
}
function getLargestFromNumericKey(keys) {
let largest = 0;
let next = 0;
for (const key of keys) {
next = parseInt(key);
if (next > largest) {
largest = next;
}
}
return largest + 1;
}
console.log("=============================================")
console.log("@ Holly's Jellyfin Library Expoter for VotV @");
console.log("@ It shouldn't have been this hard :( @");
console.log("=============================================\n");
(async () => {
console.log("Fetching users...");
const users = await apiRequest("Users");
let userId = "";
for (const user of users) {
if (user.Name === USER_NAME) {
userId = user.Id;
break;
}
}
if (userId === "") {
console.log(`Could not find user "${USER_NAME}" on the server.`);
return;
}
console.log(`Found user "${USER_NAME}", ID = ${userId}.`);
console.log(`Fetching Libraries for ${userId}...`);
const libraries = await apiRequest(`Items?userId=${userId}`);
let libraryId = "";
for (const library of libraries.Items) {
if (library.Type !== "CollectionFolder") {
continue;
}
if (library.Name === LIBRARY_NAME) {
libraryId = library.Id;
}
}
if (libraryId === "") {
console.log(`Could not find library "${LIBRARY_NAME}" for user ${userId} on the server.`)
}
console.log(`Found library "${LIBRARY_NAME}", ID = ${libraryId}`);
console.log("Fetching library media...");
const media = await apiRequest(`Items?userId=${userId}&recursive=true&parentId=${libraryId}`);
console.log("Exporting...");
const groupedSongs = new StrippedFunkyArray();
for (const item of media.Items) {
if (item.Type !== "Audio") {
if (item.Type === "MusicAlbum") {
albumCount++;
}
continue;
}
let albumArray = groupedSongs.get(item.AlbumId);
if (albumArray == null) {
albumArray = groupedSongs.set(item.AlbumId, new StrippedFunkyArray());
}
albumArray.set(item.IndexNumber ?? albumArray.undefIndex++, item);
}
for (const albumArrayKey of groupedSongs.itemKeys) {
const albumArray = groupedSongs.get(albumArrayKey);
const largestIndexNumber = getLargestFromNumericKey(albumArray.itemKeys);
for (let i = 1; i < largestIndexNumber; i++) {
if (albumArray.items[i] != null) {
const item = albumArray.items[i];
outText += `${outText.length === 0 ? "" : "\n"}${item.Name} - ${item.Album ?? item.AlbumArtist}\n${SERVER_ADDRESS}/Items/${item.Id}/Download?api_key=${API_KEY}`;
songCount++;
}
}
}
fs.writeFileSync("online.txt", outText);
console.log(`Exported ${songCount} songs from ${albumCount} albums to online.txt`);
})();