From 1174281ed9b581c841840a50a2c13c58a0f5f375 Mon Sep 17 00:00:00 2001 From: Holly Stubbs Date: Wed, 10 Apr 2024 17:00:37 +0100 Subject: [PATCH] Create exporter.js --- exporter.js | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 exporter.js diff --git a/exporter.js b/exporter.js new file mode 100644 index 0000000..48d3bc2 --- /dev/null +++ b/exporter.js @@ -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`); +})(); \ No newline at end of file