From baf333167246fab652a8f5b037bf61e4b54f8f97 Mon Sep 17 00:00:00 2001 From: Prince527 Date: Fri, 29 Mar 2024 14:41:57 -0300 Subject: [PATCH] Got Jellyfin working pretty well --- README.md | 8 +- config.example.json | 2 +- config.schema.json | 2 +- router/jellyfin/artists.js | 33 +- router/jellyfin/audio.js | 2 +- router/jellyfin/branding.js | 9 + router/jellyfin/displaypreferences.js | 34 +- router/jellyfin/genres.js | 6 +- router/jellyfin/index.js | 28 +- router/jellyfin/items.js | 179 ++---- router/jellyfin/livetv.js | 6 +- router/jellyfin/playlists.js | 74 +-- router/jellyfin/shows.js | 6 +- router/jellyfin/system.js | 30 +- router/jellyfin/users.js | 819 ++++++++++++------------ router/jellyfin/userviews.js | 60 ++ router/subsonic/createPlaylist.view.js | 6 +- router/subsonic/getAlbum.view.js | 60 +- router/subsonic/getAlbumList.view.js | 8 +- router/subsonic/getAlbumList2.view.js | 8 +- router/subsonic/getArtist.view.js | 24 +- router/subsonic/getArtistInfo.view.js | 20 +- router/subsonic/getArtistInfo2.view.js | 20 +- router/subsonic/getArtists.view.js | 8 +- router/subsonic/getLyrics.view.js | 6 +- router/subsonic/getMusicFolders.view.js | 8 +- router/subsonic/getPlaylist.view.js | 66 +- router/subsonic/getPlaylists.view.js | 8 +- router/subsonic/getRandomSongs.view.js | 38 +- router/subsonic/getScanStatus.view.js | 10 +- router/subsonic/getStarred.view.js | 78 +-- router/subsonic/getStarred2.view.js | 84 +-- router/subsonic/index.js | 8 +- router/subsonic/search2.view.js | 56 +- router/subsonic/search3.view.js | 78 +-- router/subsonic/star.view.js | 4 +- router/subsonic/startScan.view.js | 10 +- router/subsonic/unstar.view.js | 4 +- router/subsonic/updatePlaylist.view.js | 4 +- 39 files changed, 981 insertions(+), 933 deletions(-) create mode 100644 router/jellyfin/branding.js create mode 100644 router/jellyfin/userviews.js diff --git a/README.md b/README.md index 5938b3c..a992349 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,15 @@ ## Supported - [Subsonic](https://www.subsonic.org/pages/index.jsp) *(75%)* -- [Jellyfin](https://jellyfin.org/)* +- [Jellyfin](https://jellyfin.org/) *(40%)* - [Euterpe](https://listen-to-euterpe.eu/) *(100%)* -> *Jellyfin support is under heavy development and should not be used at the current moment. +> Note: Client compatibility varies; the percentages reflect my experience with client compatibility, not the entire API. ## Images -| ![Euterpe](https://api.serversmp.xyz/upload/66002233195e65d6b608bc1e.webp) Euterpe | ![Subtracks](https://api.serversmp.xyz/upload/66002232195e65d6b608bc1c.webp) Subtracks | ![Ultrasonic](https://api.serversmp.xyz/upload/6600222d195e65d6b608bc1a.webp) Ultrasonic | -|------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------| +| ![Euterpe](https://api.serversmp.xyz/upload/66002233195e65d6b608bc1e.webp) Euterpe | ![Subtracks](https://api.serversmp.xyz/upload/66002232195e65d6b608bc1c.webp) Subtracks | ![Ultrasonic](https://api.serversmp.xyz/upload/6600222d195e65d6b608bc1a.webp) Ultrasonic | ![Finamp](https://api.serversmp.xyz/upload/6606fcd5195e65d6b608c1e6.webp) Finamp | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| ## Docker diff --git a/config.example.json b/config.example.json index 2a297df..0dc13e5 100644 --- a/config.example.json +++ b/config.example.json @@ -4,7 +4,7 @@ "url": "http://ip:port", // url of this api "api": { // enable of disable api implementation "subsonic": true, - "jellyfin": false, // I would disable jellyfin for now, its a work in progress + "jellyfin": true, "euterpe": true }, "users": [ // list of users, if the array is empty then authentication is disabled diff --git a/config.schema.json b/config.schema.json index a01c066..0ed2067 100644 --- a/config.schema.json +++ b/config.schema.json @@ -4,7 +4,7 @@ "url": "http://ip:port", "api": { "subsonic": true, - "jellyfin": false, + "jellyfin": true, "euterpe": true }, "users": [ diff --git a/router/jellyfin/artists.js b/router/jellyfin/artists.js index b74c9dd..b26ffbc 100644 --- a/router/jellyfin/artists.js +++ b/router/jellyfin/artists.js @@ -2,32 +2,23 @@ const express = require("express"); const router = express.Router(); router.get("/albumartists", async(req, res) => { - let { StartIndex, Limit } = req.query; + const { StartIndex = "0", Limit = "50" } = req.query; - const artists = await (await fetch(`${global.config.music}/getall/artists?start=${StartIndex || '0'}&limit=${Limit || '50'}&sortby=created_date&reverse=1`)).json(); + const artists = await (await fetch(`${global.config.music}/getall/artists?start=${StartIndex}&limit=${Limit}&sortby=created_date&reverse=1`)).json(); - const output = artists.items.map(artist => ({ - "Name": artist.name, - "ServerId": "server", - "Id": artist.artisthash, - "SortName": artist.name, - "ChannelId": null, - "RunTimeTicks": 0, - "Type": "MusicArtist", - "UserData": { - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "IsFavorite": false, - "Played": false - }, - "PrimaryImageAspectRatio": 1, - "LocationType": "FileSystem" + const items = artists.items.map(artist => ({ + Name: artist.name, + Id: artist.artisthash, + Type: "MusicArtist", + UserData: { PlaybackPositionTicks: 0, PlayCount: 0, IsFavorite: false, Played: false }, + PrimaryImageAspectRatio: 1, + LocationType: "FileSystem" })); res.json({ - "Items": output, - "TotalRecordCount": artists.total, - "StartIndex": 0 + Items: items, + TotalRecordCount: artists.total, + StartIndex: Number(StartIndex) }); }); diff --git a/router/jellyfin/audio.js b/router/jellyfin/audio.js index 310ef44..f0b5591 100644 --- a/router/jellyfin/audio.js +++ b/router/jellyfin/audio.js @@ -3,7 +3,7 @@ const router = express.Router(); const proxy = require("../../packages/proxy"); -router.get("/:id/universal", async(req, res) => { +router.get("/:id/*", async(req, res) => { const id = req.params.id; const url = `${global.config.music}/file/${id}`; diff --git a/router/jellyfin/branding.js b/router/jellyfin/branding.js new file mode 100644 index 0000000..4531588 --- /dev/null +++ b/router/jellyfin/branding.js @@ -0,0 +1,9 @@ +const express = require("express"); +const router = express.Router(); + +router.all("/*", (req, res) => res.send("ok")); + +module.exports = { + router: router, + name: "branding" +} \ No newline at end of file diff --git a/router/jellyfin/displaypreferences.js b/router/jellyfin/displaypreferences.js index 1655e97..d1ec64f 100644 --- a/router/jellyfin/displaypreferences.js +++ b/router/jellyfin/displaypreferences.js @@ -1,26 +1,20 @@ const express = require("express"); const router = express.Router(); -router.route("/usersettings") - .post(userSettings) - .get(userSettings); - -function userSettings(req, res) { - res.json({ - "Id": "user", - "SortBy": "SortName", - "RememberIndexing": true, - "PrimaryImageHeight": 0, - "PrimaryImageWidth": 0, - "CustomPrefs": {}, - "ScrollDirection": "Horizontal", - "ShowBackdrop": false, - "RememberSorting": true, - "SortOrder": "Ascending", - "ShowSidebar": true, - "Client": "emby" - }); -} +router.all("/usersettings", async(req, res) => res.json({ + Id: "user", + SortBy: "SortName", + RememberIndexing: true, + PrimaryImageHeight: 0, + PrimaryImageWidth: 0, + CustomPrefs: {}, + ScrollDirection: "Horizontal", + ShowBackdrop: false, + RememberSorting: true, + SortOrder: "Ascending", + ShowSidebar: true, + Client: "emby" +})) module.exports = { router: router, diff --git a/router/jellyfin/genres.js b/router/jellyfin/genres.js index b88fafa..89daa94 100644 --- a/router/jellyfin/genres.js +++ b/router/jellyfin/genres.js @@ -2,9 +2,9 @@ const express = require("express"); const router = express.Router(); router.all("/*", (req, res) => res.json({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 + Items: [], + TotalRecordCount: 0, + StartIndex: 0 })); module.exports = { diff --git a/router/jellyfin/index.js b/router/jellyfin/index.js index 0492737..0656a59 100644 --- a/router/jellyfin/index.js +++ b/router/jellyfin/index.js @@ -1,5 +1,24 @@ const { getFileList } = require("../../packages/files"); +async function checkAuth(req, res, next) { + const login = ["/branding/configuration", "/displaypreferences/usersettings", "/playback/bitratetest", "/quickconnect/enabled", "/sessions/capabilities/full", "/system/endpoint", "/system/info", "/system/info/public", "/users/authenticatebyname", "/users/public", "/users/user", "/userviews/","/branding/css"]; + + const { server } = global.config; + + if (server.users.length && !login.includes(`${req.baseUrl.toLowerCase()}${req.path.toLowerCase()}`)) { + const tokenHeader = req.headers["x-emby-token"] || req.headers["x-emby-authorization"] || req.headers["x-mediabrowser-token"] || req.headers["authorization"] || req.query.api_key || req.query.ApiKey; + if (!tokenHeader) return res.sendStatus(401); + + const token = tokenHeader.includes('Token=') ? tokenHeader.match(/Token="([^"]*)"/)?.[1] : tokenHeader; + if (!token) return res.sendStatus(401); + + const [username, password] = token.split("@"); + if (!server.users.some(user => user.username === username && user.password === password)) return res.sendStatus(401); + } + + next(); +} + module.exports = async(app) => { const routeFiles = await getFileList(`${process.cwd()}/router/jellyfin`, { type: ".js", recursively: false }); @@ -7,7 +26,12 @@ module.exports = async(app) => { if (!value.includes("index.js")) { const { name, router } = require(value); - app.use(`/${name}`, router); + const exclude = ["audio", "items"]; + + if (!exclude.includes(name)) app.use(`/${name}`, checkAuth, router); + else app.use(`/${name}`, router); } }); -} \ No newline at end of file +} + +module.exports.checkAuth = checkAuth; \ No newline at end of file diff --git a/router/jellyfin/items.js b/router/jellyfin/items.js index 33ad415..706a8a4 100644 --- a/router/jellyfin/items.js +++ b/router/jellyfin/items.js @@ -2,147 +2,100 @@ const express = require("express"); const router = express.Router(); const proxy = require("../../packages/proxy"); +const { checkAuth } = require("./index"); router.get("/:id/images/primary", async(req, res) => { - let id = req.params.id; + const id = req.params.id; const artist = await fetch(`${global.config.music}/artist/${id}/albums?limit=1&all=false`); - // const albumSize = await (await fetch(`${global.config.music}/getall/albums?start=0&limit=1&sortby=created_date&reverse=1`)).json(); - // const albums = await (await fetch(`${global.config.music}/getall/albums?start=0&limit=${albumSize.total}&sortby=created_date&reverse=1`)).json(); - - // for (let index = 0; index < albums.items.length; index++) { - // const album = albums.items[index]; - - // const tracks = await (await fetch(`${global.config.music}/album`, { - // method: "POST", - // headers: { - // "Content-Type": "application/json" - // }, - // body: JSON.stringify({ albumhash: album.albumhash }) - // })).json(); - - // if (tracks.tracks.find(track => track.trackhash === id)) { - // id = tracks.info.albumhash; - // break; - // } - // } - const cover = `${global.config.music}/img/${artist.ok ? 'a': 't'}/${id}.webp`; if (global.config.server.proxy) proxy(res, cover); else res.redirect(cover); }); -router.get("/:id/file", async(req, res) => { - const id = req.params.id; - - const url = `${global.config.music}/file/${id}`; - - if (global.config.server.proxy) proxy(res, url); - else res.redirect(url); -}); +router.use("/:id/file", checkAuth, getFile); +router.use("/:id/download", checkAuth, getFile); -router.get("/:id/download", async(req, res) => { +async function getFile(req, res) { const id = req.params.id; const url = `${global.config.music}/file/${id}`; if (global.config.server.proxy) proxy(res, url); else res.redirect(url); -}); +} -router.get("/:id/thememedia", (req, res) => res.json({ - "ThemeVideosResult": { - "OwnerId": "00000000000000000000000000000000", - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }, - "ThemeSongsResult": { - "OwnerId": "00000000000000000000000000000000", - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }, - "SoundtrackSongsResult": { - "OwnerId": "00000000000000000000000000000000", - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - } +router.get("/:id/thememedia", checkAuth, (req, res) => res.json({ + ThemeVideosResult: { items: [], totalRecordCount: 0, startIndex: 0 }, + ThemeSongsResult: { items: [], totalRecordCount: 0, startIndex: 0 }, + SoundtrackSongsResult: { items: [], totalRecordCount: 0, startIndex: 0 } })); -router.get("/:id/playbackinfo", (req, res) => { +router.use("/:id/playbackinfo", checkAuth); + +router.route("/:id/playbackinfo") + .post(playBackInfo) + .get(playBackInfo) + +async function playBackInfo(req, res) { const { id } = req.params; res.json({ - "MediaSources": [{ - "Protocol": "File", - "Id": id, - "Path": `/items/${id}/download`, - "Type": "Default", - "Container": "mp3", - "Size": 0, - "Name": id, - "IsRemote": false, - "ETag": id, - "RunTimeTicks": 0, - "ReadAtNativeFramerate": false, - "IgnoreDts": false, - "IgnoreIndex": false, - "GenPtsInput": false, - "SupportsTranscoding": false, - "SupportsDirectStream": true, - "SupportsDirectPlay": true, - "IsInfiniteStream": false, - "RequiresOpening": false, - "RequiresClosing": false, - "RequiresLooping": false, - "SupportsProbing": true, - "MediaStreams": [{ - "Codec": "mp3", - "TimeBase": "1/14112000", - "DisplayTitle": "MP3 - Stereo", - "IsInterlaced": false, - "ChannelLayout": "stereo", - "BitRate": 0, - "Channels": 0, - "SampleRate": 0, - "IsDefault": false, - "IsForced": false, - "Type": "Audio", - "Index": 0, - "IsExternal": false, - "IsTextSubtitleStream": false, - "SupportsExternalStream": false, - "Level": 0 + MediaSources: [{ + Protocol: "File", + Id: id, + Path: `/items/${id}/download`, + Type: "Default", + Container: "mp3", + Size: 0, + Name: id, + IsRemote: false, + ETag: id, + RunTimeTicks: 0, + ReadAtNativeFramerate: false, + IgnoreDts: false, + IgnoreIndex: false, + GenPtsInput: false, + SupportsTranscoding: false, + SupportsDirectStream: true, + SupportsDirectPlay: true, + IsInfiniteStream: false, + RequiresOpening: false, + RequiresClosing: false, + RequiresLooping: false, + SupportsProbing: true, + MediaStreams: [{ + Codec: "mp3", + TimeBase: "1/14112000", + DisplayTitle: "MP3 - Stereo", + IsInterlaced: false, + ChannelLayout: "stereo", + BitRate: 0, + Channels: 0, + SampleRate: 0, + IsDefault: false, + IsForced: false, + Type: "Audio", + Index: 0, + IsExternal: false, + IsTextSubtitleStream: false, + SupportsExternalStream: false, + Level: 0 }], - "MediaAttachments": [], - "Formats": [], - "Bitrate": 0, - "RequiredHttpHeaders": {}, - "DefaultAudioStreamIndex": 0 + MediaAttachments: [], + Formats: [], + Bitrate: 0, + RequiredHttpHeaders: {}, + DefaultAudioStreamIndex: 0 }], - "PlaySessionId": "9f584e0d261a4c9fb2da3528565869ca" + PlaySessionId: "session" }); -}); +} -router.get("/", async(req, res) => { - res.json({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }); -}); - -router.get("/:id/similar", async(req, res) => { - res.json({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }); -}); +router.get("/", checkAuth, (req, res) => res.json({ Items: [], TotalRecordCount: 0, StartIndex: 0 })); +router.get("/:id/similar", checkAuth, (req, res) => res.json({ Items: [], TotalRecordCount: 0, StartIndex: 0 })); module.exports = { router: router, diff --git a/router/jellyfin/livetv.js b/router/jellyfin/livetv.js index 5b0cd27..ba5668e 100644 --- a/router/jellyfin/livetv.js +++ b/router/jellyfin/livetv.js @@ -2,9 +2,9 @@ const express = require("express"); const router = express.Router(); router.get("/programs/recommended", (req, res) => res.json({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 + Items: [], + TotalRecordCount: 0, + StartIndex: 0 })); module.exports = { diff --git a/router/jellyfin/playlists.js b/router/jellyfin/playlists.js index 4536b70..82a9f88 100644 --- a/router/jellyfin/playlists.js +++ b/router/jellyfin/playlists.js @@ -6,54 +6,46 @@ router.get("/:id/items", async(req, res) => { const playlist = await (await fetch(`${global.config.music}/playlist/${id}?no_tracks=false`)).json(); - const output = playlist.tracks.map(track => ({ - "Name": track.title, - "ServerId": "server", - "Id": track.trackhash, - "PlaylistItemId": "34536289380943e5b15e40b30f009d9c", - "PremiereDate": "2010-02-03T00:00:00.0000000Z", - "ChannelId": null, - "RunTimeTicks": Math.round(track.duration * 9962075.847328244), - "ProductionYear": 0, - "IndexNumber": track.track, - "ParentIndexNumber": track.track, - "IsFolder": false, - "Type": "Audio", - "UserData": { - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "IsFavorite": false, - "LastPlayedDate": "2024-03-04T22:45:04.3646553Z", - "Played": true - }, - "PrimaryImageAspectRatio": 1, - "Artists": track.artists.map(artist => artist.name), - "ArtistItems": track.artists.map(artist => ({ - "Name": artist.name, - "Id": artist.artisthash + const items = playlist.tracks.map(track => ({ + Name: track.title, + ServerId: "server", + Id: track.trackhash, + PlaylistItemId: track.trackhash, + PremiereDate: "2010-02-03T00:00:00.0000000Z", + RunTimeTicks: Math.round(track.duration * 9962075.847328244), + IndexNumber: track.track, + ParentIndexNumber: track.track, + IsFolder: false, + Type: "Audio", + UserData: { PlaybackPositionTicks: 0, PlayCount: 0, IsFavorite: false, Played: false }, + PrimaryImageAspectRatio: 1, + Artists: track.artists.map(artist => artist.name), + ArtistItems: track.artists.map(artist => ({ + Name: artist.name, + Id: artist.artisthash })), - "Album": track.album, - "AlbumId": track.albumhash, - "AlbumPrimaryImageTag": track.albumhash, - "AlbumArtist": "阿保剛", - "AlbumArtists": track.albumartists.map(artist => ({ - "Name": artist.name, - "Id": artist.artisthash + Album: track.album, + AlbumId: track.albumhash, + AlbumPrimaryImageTag: track.albumhash, + AlbumArtist: track.albumartists[0].name, + AlbumArtists: track.albumartists.map(artist => ({ + Name: artist.name, + Id: artist.artisthash })), - "ImageTags": { - "Primary": track.albumhash + ImageTags: { + Primary: track.albumhash }, - "BackdropImageTags": [], - "LocationType": "FileSystem", - "MediaType": "Audio" + BackdropImageTags: [], + LocationType: "FileSystem", + MediaType: "Audio" })); res.json({ - "Items": output, - "TotalRecordCount": playlist.info.count, - "StartIndex": 0 + Items: items, + TotalRecordCount: playlist.info.count, + StartIndex: 0 }); -}) +}); module.exports = { router: router, diff --git a/router/jellyfin/shows.js b/router/jellyfin/shows.js index 8337760..8f6e63a 100644 --- a/router/jellyfin/shows.js +++ b/router/jellyfin/shows.js @@ -2,9 +2,9 @@ const express = require("express"); const router = express.Router(); router.get("/nextup", (req, res) => res.json({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 + Items: [], + TotalRecordCount: 0, + StartIndex: 0 })); module.exports = { diff --git a/router/jellyfin/system.js b/router/jellyfin/system.js index 42befbb..ff62743 100644 --- a/router/jellyfin/system.js +++ b/router/jellyfin/system.js @@ -1,29 +1,19 @@ const express = require("express"); const router = express.Router(); -router.get("/info", (req, res) => res.json({ - "LocalAddress": global.config.server.url, - "ServerName": "Swingfin", - "Version": "10.8.13", - "ProductName": "Swingfin Server", - "OperatingSystem": "Nodejs", - "Id": "server", - "StartupWizardCompleted": true -})); - -router.get("/info/public", (req, res) => res.json({ - "LocalAddress": global.config.server.url, - "ServerName": "Swingfin", - "Version": "10.8.13", - "ProductName": "Swingfin Server", - "OperatingSystem": "Nodejs", - "Id": "server", - "StartupWizardCompleted": true +router.get("/info*", (req, res) => res.json({ + LocalAddress: global.config.server.url, + ServerName: "Swingfin", + Version: "10.8.13", + ProductName: "Swingfin Server", + OperatingSystem: "Nodejs", + Id: "server", + StartupWizardCompleted: true })); router.get("/endpoint", (req, res) => res.json({ - "IsLocal": true, - "IsInNetwork": true + IsLocal: true, + IsInNetwork: true })); module.exports = { diff --git a/router/jellyfin/users.js b/router/jellyfin/users.js index 6a2fd5e..eeaf0ab 100644 --- a/router/jellyfin/users.js +++ b/router/jellyfin/users.js @@ -3,7 +3,7 @@ const router = express.Router(); router.get("/public", (req, res) => res.json([])); -router.get("/:id/views", async(req, res) => { +router.get("/user/views", async(req, res) => { const folders = await (await fetch(`${global.config.music}/folder`, { method: "POST", headers: { @@ -15,126 +15,136 @@ router.get("/:id/views", async(req, res) => { }) })).json(); + const items = folders.folders.map(folder => ({ + Name: folder.name, + ServerId: "server", + Id: folder.name, + Etag: "tag", + DateCreated: "2024-03-04T00:39:17.500887Z", + CanDelete: false, + CanDownload: false, + SortName: "music", + ExternalUrls: [], + Path: folder.path, + EnableMediaSourceDisplay: true, + ChannelId: null, + Taglines: [], + Genres: [], + RemoteTrailers: [], + ProviderIds: {}, + IsFolder: true, + ParentId: "0", + Type: "CollectionFolder", + People: [], + Studios: [], + GenreItems: [], + LocalTrailerCount: 0, + SpecialFeatureCount: 0, + DisplayPreferencesId: "folder", + Tags: [], + CollectionType: "music", + LocationType: "FileSystem", + LockedFields: [], + LockData: false + })); + res.json({ - "Items": folders.folders.map(folder => ({ - "Name": folder.name, - "ServerId": "server", - "Id": folder.path, - "Etag": "tag", - "DateCreated": "2024-03-04T00:39:17.500887Z", - "CanDelete": false, - "CanDownload": false, - "SortName": "music", - "ExternalUrls": [], - "Path": folder.path, - "EnableMediaSourceDisplay": true, - "ChannelId": null, - "Taglines": [], - "Genres": [], - "RemoteTrailers": [], - "ProviderIds": {}, - "IsFolder": true, - "ParentId": "0", - "Type": "CollectionFolder", - "People": [], - "Studios": [], - "GenreItems": [], - "LocalTrailerCount": 0, - "SpecialFeatureCount": 0, - "DisplayPreferencesId": "folder", - "Tags": [], - "CollectionType": "music", - "LocationType": "FileSystem", - "LockedFields": [], - "LockData": false - })), - "TotalRecordCount": folders.folders.length, - "StartIndex": 0 + Items: items, + TotalRecordCount: items.length, + StartIndex: 0, + ServerId: "server" }); }); router.route("/authenticatebyname") .post(sendUser) - .get(sendUser) + .get(sendUser); router.get("/user", sendUser); function sendUser(req, res) { - res.json({ - "User": { - "Name": "test", - "ServerId": "server", - "Id": "user", - "HasPassword": true, - "HasConfiguredPassword": true, - "HasConfiguredEasyPassword": false, - "EnableAutoLogin": false, - "LastLoginDate": "2024-03-04T19:59:39.5813857Z", - "LastActivityDate": "2024-03-04T19:59:39.5813857Z", - "Configuration": { - "PlayDefaultAudioTrack": true, - "SubtitleLanguagePreference": "", - "DisplayMissingEpisodes": false, - "GroupedFolders": [], - "SubtitleMode": "Default", - "DisplayCollectionsView": false, - "EnableLocalPassword": false, - "OrderedViews": [], - "LatestItemsExcludes": [], - "MyMediaExcludes": [], - "HidePlayedInLatest": true, - "RememberAudioSelections": true, - "RememberSubtitleSelections": true, - "EnableNextEpisodeAutoPlay": true - }, - "Policy": { - "IsAdministrator": true, - "IsHidden": true, - "IsDisabled": false, - "BlockedTags": [], - "EnableUserPreferenceAccess": true, - "AccessSchedules": [], - "BlockUnratedItems": [], - "EnableRemoteControlOfOtherUsers": true, - "EnableSharedDeviceControl": true, - "EnableRemoteAccess": true, - "EnableLiveTvManagement": true, - "EnableLiveTvAccess": true, - "EnableMediaPlayback": true, - "EnableAudioPlaybackTranscoding": true, - "EnableVideoPlaybackTranscoding": true, - "EnablePlaybackRemuxing": true, - "ForceRemoteSourceTranscoding": false, - "EnableContentDeletion": true, - "EnableContentDeletionFromFolders": [], - "EnableContentDownloading": true, - "EnableSyncTranscoding": true, - "EnableMediaConversion": true, - "EnabledDevices": [], - "EnableAllDevices": true, - "EnabledChannels": [], - "EnableAllChannels": true, - "EnabledFolders": [], - "EnableAllFolders": true, - "InvalidLoginAttemptCount": 0, - "LoginAttemptsBeforeLockout": -1, - "MaxActiveSessions": 0, - "EnablePublicSharing": true, - "BlockedMediaFolders": [], - "BlockedChannels": [], - "RemoteClientBitrateLimit": 0, - "AuthenticationProviderId": "Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider", - "PasswordResetProviderId": "Jellyfin.Server.Implementations.Users.DefaultPasswordResetProvider", - "SyncPlayAccess": "CreateAndJoinGroups" - } + const { Pw: password, Username: username } = req.body; + + console.log(`${req.baseUrl.toLowerCase()}${req.path.toLowerCase()}`) + + const userSettings = { + Name: username, + ServerId: "server", + Id: "user", + AccessToken: `${username}@${password}`, + HasPassword: true, + HasConfiguredPassword: true, + HasConfiguredEasyPassword: false, + EnableAutoLogin: false, + LastLoginDate: "2024-03-04T19:59:39.5813857Z", + LastActivityDate: "2024-03-04T19:59:39.5813857Z", + Policy: { + IsAdministrator: true, + IsHidden: true, + IsDisabled: false, + BlockedTags: [], + EnableUserPreferenceAccess: true, + AccessSchedules: [], + BlockUnratedItems: [], + EnableRemoteControlOfOtherUsers: true, + EnableSharedDeviceControl: true, + EnableRemoteAccess: true, + EnableLiveTvManagement: true, + EnableLiveTvAccess: true, + EnableMediaPlayback: true, + EnableAudioPlaybackTranscoding: true, + EnableVideoPlaybackTranscoding: true, + EnablePlaybackRemuxing: true, + ForceRemoteSourceTranscoding: false, + EnableContentDeletion: true, + EnableContentDeletionFromFolders: [], + EnableContentDownloading: true, + EnableSyncTranscoding: true, + EnableMediaConversion: true, + EnabledDevices: [], + EnableAllDevices: true, + EnabledChannels: [], + EnableAllChannels: true, + EnabledFolders: [], + EnableAllFolders: true, + InvalidLoginAttemptCount: 0, + LoginAttemptsBeforeLockout: -1, + MaxActiveSessions: 0, + EnablePublicSharing: true, + BlockedMediaFolders: [], + BlockedChannels: [], + RemoteClientBitrateLimit: 0, + AuthenticationProviderId: "Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider", + PasswordResetProviderId: "Jellyfin.Server.Implementations.Users.DefaultPasswordResetProvider", + SyncPlayAccess: "CreateAndJoinGroups" }, - "AccessToken": "user@password", - "ServerId": "server" + Configuration: { + PlayDefaultAudioTrack: true, + SubtitleLanguagePreference: "", + DisplayMissingEpisodes: false, + GroupedFolders: [], + SubtitleMode: "Default", + DisplayCollectionsView: false, + EnableLocalPassword: false, + OrderedViews: [], + LatestItemsExcludes: [], + MyMediaExcludes: [], + HidePlayedInLatest: true, + RememberAudioSelections: true, + RememberSubtitleSelections: true, + EnableNextEpisodeAutoPlay: true + } + } + + res.json({ + User: userSettings, + ...userSettings, }); } -router.get("/:user/items", async(req, res) => { - let { IncludeItemTypes, Limit, StartIndex, ParentId, AlbumArtistIds, Ids } = req.query; +// NOTE: This function still need to be refactored +router.get("/user/items", async(req, res) => { + let { IncludeItemTypes, Limit, StartIndex, ParentId, AlbumArtistIds, Ids, MediaTypes } = req.query; if (ParentId && IncludeItemTypes === "Audio") { const folders = await (await fetch(`${global.config.music}/folder`, { @@ -161,7 +171,7 @@ router.get("/:user/items", async(req, res) => { let output = []; let albums = []; - if ((IncludeItemTypes === "MusicAlbum" && !AlbumArtistIds) || (!IncludeItemTypes && !AlbumArtistIds)) { + if ((IncludeItemTypes === "MusicAlbum" && !AlbumArtistIds) || (!IncludeItemTypes && !AlbumArtistIds && !MediaTypes)) { albums = await (await fetch(`${global.config.music}/getall/albums?start=${StartIndex || '0'}&limit=${Limit || '50'}&sortby=created_date&reverse=1`)).json(); output = await Promise.all(await albums.items.map(async(album) => { @@ -244,72 +254,141 @@ router.get("/:user/items", async(req, res) => { "BackdropImageTags": [], "LocationType": "FileSystem" })); - } else if (IncludeItemTypes === "Audio" && ParentId) { - albums = await (await fetch(`${global.config.music}/album`, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ albumhash: ParentId }) - })).json(); + } else if ((IncludeItemTypes === "Audio" || MediaTypes === "Audio,Video") && ParentId) { + try { + albums = await (await fetch(`${global.config.music}/album`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ albumhash: ParentId }) + })).json(); - albums.total = albums.tracks.length; + if (albums?.error) { + albums = await (await fetch(`${global.config.music}/playlist/${ParentId}?no_tracks=false`)).json(); + console.log(albums) + } - output = albums.tracks.map(track => ({ - "Album": track.album, - "AlbumArtist": track.albumartists[0].name, - "AlbumArtists": albums.info.albumartists.map(artist => ({ - "Id": artist.artisthash, - "Name": artist.name - })), - "AlbumId": track.albumhash, - "AlbumPrimaryImageTag": track.trackhash, - "ArtistItems": track.artists.map(artist => ({ - "Id": artist.artisthash, - "Name": artist.name - })), - "Artists": track.artists.map(artist => artist.name), - "BackdropImageTags": [], - "ChannelId": null, - "ChildCount": 0, - "Etag": track.trackhash, - "Genres": [ - "Unknown" - ], - "Id": track.trackhash, - "ImageTags": { - "Primary": track.albumhash - }, - "IndexNumber": track.track, - "IndexNumberEnd": albums.total, - "IsFolder": false, - "LocationType": "FileSystem", - "MediaType": "Audio", - "Name": track.title, - "ParentIndexNumber": 1, - "ParentPrimaryImageItemId": track.albumhash, - "PremiereDate": "2010-02-03T00:00:00.0000000Z", // change - "ProductionYear": albums.info.date, - "ProviderIds": {}, - "RunTimeTicks": Math.round(track.duration * 9962075.847328244), - "ServerId": "server", - "SongCount": albums.total, - "Tags": [ - "Unknown" - ], - "Type": "Audio", - "UserData": { - "IsFavorite": track.is_favorite, - "LastPlayedDate": "2019-08-24T14:15:22Z", // change - "Likes": false, - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "Played": false, - "PlayedPercentage": 0, - "Rating": 0, - "UnplayedItemCount": 0 + albums.total = albums.tracks.length; + + if (albums.info?.albumartists) { + output = albums.tracks.map(track => ({ + "Album": track.album, + "AlbumArtist": track.albumartists[0].name, + "AlbumArtists": albums.info.albumartists.map(artist => ({ + "Id": artist.artisthash, + "Name": artist.name + })), + "AlbumId": track.albumhash, + "AlbumPrimaryImageTag": track.trackhash, + "ArtistItems": track.artists.map(artist => ({ + "Id": artist.artisthash, + "Name": artist.name + })), + "Artists": track.artists.map(artist => artist.name), + "BackdropImageTags": [], + "ChannelId": null, + "ChildCount": 0, + "Etag": track.trackhash, + "Genres": [ + "Unknown" + ], + "Id": track.trackhash, + "ImageTags": { + "Primary": track.albumhash + }, + "IndexNumber": track.track, + "IndexNumberEnd": albums.total, + "IsFolder": false, + "LocationType": "FileSystem", + "MediaType": "Audio", + "Name": track.title, + "ParentIndexNumber": 1, + "ParentPrimaryImageItemId": track.albumhash, + "PremiereDate": "2010-02-03T00:00:00.0000000Z", // change + "ProductionYear": albums.info.date, + "ProviderIds": {}, + "RunTimeTicks": Math.round(track.duration * 9962075.847328244), + "ServerId": "server", + "SongCount": albums.total, + "Tags": [ + "Unknown" + ], + "Type": "Audio", + "UserData": { + "IsFavorite": track.is_favorite, + "LastPlayedDate": "2019-08-24T14:15:22Z", // change + "Likes": false, + "PlaybackPositionTicks": 0, + "PlayCount": 0, + "Played": false, + "PlayedPercentage": 0, + "Rating": 0, + "UnplayedItemCount": 0, + "Key": track.albumhash + } + })); + } else { + output = albums.tracks.map(track => ({ + "Album": track.album, + "AlbumArtist": track.albumartists[0].name, + "AlbumArtists": track.albumartists.map(artist => ({ + "Id": artist.artisthash, + "Name": artist.name + })), + "AlbumId": track.albumhash, + "AlbumPrimaryImageTag": track.trackhash, + "ArtistItems": track.artists.map(artist => ({ + "Id": artist.artisthash, + "Name": artist.name + })), + "Artists": track.artists.map(artist => artist.name), + "BackdropImageTags": [], + "ChannelId": null, + "ChildCount": 0, + "Etag": track.trackhash, + "Genres": [ + "Unknown" + ], + "Id": track.trackhash, + "ImageTags": { + "Primary": track.albumhash + }, + "IndexNumber": track.track, + "IndexNumberEnd": albums.total, + "IsFolder": false, + "LocationType": "FileSystem", + "MediaType": "Audio", + "Name": track.title, + "ParentIndexNumber": 1, + "ParentPrimaryImageItemId": track.albumhash, + "PremiereDate": "2010-02-03T00:00:00.0000000Z", // change + "ProductionYear": track.date, + "ProviderIds": {}, + "RunTimeTicks": Math.round(track.duration * 9962075.847328244), + "ServerId": "server", + "SongCount": albums.total, + "Tags": [ + "Unknown" + ], + "Type": "Audio", + "UserData": { + "IsFavorite": track.is_favorite, + "LastPlayedDate": "2019-08-24T14:15:22Z", // change + "Likes": false, + "PlaybackPositionTicks": 0, + "PlayCount": 0, + "Played": false, + "PlayedPercentage": 0, + "Rating": 0, + "UnplayedItemCount": 0, + "Key": track.albumhash + } + })); } - })); + } catch(err) { + + } } else if (IncludeItemTypes === "Playlist") { albums = await (await fetch(`${global.config.music}/playlists`)).json(); albums.total = albums.data.length; @@ -505,140 +584,162 @@ router.get("/:user/items", async(req, res) => { }); }); -router.get("/:user/items/:id", async(req, res) => { +router.get("/user/items/:id", async(req, res) => { const id = req.params.id; - const albums = await (await fetch(`${global.config.music}/album`, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ albumhash: id }) - })).json(); + try { + const albums = await (await fetch(`${global.config.music}/album`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ albumhash: id }) + })).json(); - albums.total = albums.tracks.length; - - const output = albums.tracks.map(track => ({ - "Album": track.album, - "AlbumArtist": track.albumartists[0].name, - "AlbumArtists": albums.info.albumartists.map(artist => ({ - "Id": artist.artisthash, - "Name": artist.name - })), - "AlbumId": track.albumhash, - "AlbumPrimaryImageTag": track.trackhash, - "ArtistItems": track.artists.map(artist => ({ - "Id": artist.artisthash, - "Name": artist.name - })), - "Artists": track.artists.map(artist => artist.name), - "BackdropImageTags": [], - "ChannelId": null, - "ChildCount": 0, - "Etag": track.trackhash, - "Genres": [ - "Unknown" - ], - "Id": track.trackhash, - "ImageTags": { - "Primary": track.albumhash - }, - "IndexNumber": track.track, - "IndexNumberEnd": albums.total, - "IsFolder": false, - "LocationType": "FileSystem", - "MediaType": "Audio", - "Name": track.title, - "ParentIndexNumber": 1, - "ParentPrimaryImageItemId": track.albumhash, - "PremiereDate": "2010-02-03T00:00:00.0000000Z", // change - "ProductionYear": albums.info.date, - "ProviderIds": {}, - "RunTimeTicks": Math.round(track.duration * 9962075.847328244), - "ServerId": "server", - "SongCount": albums.total, - "Tags": [ - "Unknown" - ], - "Type": "Audio", - "UserData": { - "IsFavorite": track.is_favorite, - "LastPlayedDate": "2019-08-24T14:15:22Z", // change - "Likes": false, - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "Played": false, - "PlayedPercentage": 0, - "Rating": 0, - "UnplayedItemCount": 0 + if (albums?.error) { + const playlist = await (await fetch(`${global.config.music}/playlist/${id}?no_tracks=false`)).json(); + + const items = playlist.tracks.map(track => ({ + Album: track.album, + AlbumArtist: track.artists[0].name, + AlbumArtists: track.artists.map(artist => ({ Id: artist.artisthash, Name: artist.name })), + AlbumId: track.albumhash, + AlbumPrimaryImageTag: track.trackhash, + ArtistItems: track.artists.map(artist => ({ Id: artist.artisthash, Name: artist.name })), + Artists: track.artists.map(artist => artist.name), + BackdropImageTags: [], + ChannelId: null, + ChildCount: 0, + Etag: track.trackhash, + Genres: ["Unknown"], + Id: track.trackhash, + ImageTags: { Primary: track.albumhash }, + IndexNumber: track.track, + IndexNumberEnd: playlist.tracks.length, + IsFolder: false, + LocationType: "FileSystem", + MediaType: "Audio", + Name: track.title, + ParentIndexNumber: 1, + ParentPrimaryImageItemId: track.albumhash, + PremiereDate: "2010-02-03T00:00:00.0000000Z", + ProductionYear: track.created_date, + ProviderIds: {}, + RunTimeTicks: Math.round(track.duration * 9962075.847328244), + ServerId: "server", + SongCount: playlist.tracks.length, + Tags: ["Unknown"], + Type: "Audio", + UserData: { PlaybackPositionTicks: 0, PlayCount: 0, IsFavorite: false, Played: false } + })); + + return res.json({ + Items: items, + TotalRecordCount: playlist.info.count, + StartIndex: 0, + ServerId: "server" + }); } - })); - res.json({ - "Items": output, - "TotalRecordCount": albums.total, - "StartIndex": 0, - "Name": albums.info.title, - "ServerId": "server", - "Id": albums.info.albumhash, - "Etag": albums.info.albumhash, - "DateCreated": "2024-03-04T00:39:33.730766Z", - "CanDelete": true, - "CanDownload": false, - "SortName": albums.info.title, - "PremiereDate": "2010-02-03T00:00:00.0000000Z", - "ExternalUrls": [], - "Path": "undefined", - "EnableMediaSourceDisplay": true, - "ChannelId": null, - "Taglines": [], - "Genres": albums.info.genres, - "CumulativeRunTimeTicks": Math.round(albums.info.duration * 9962075.847328244), - "RunTimeTicks": Math.round(albums.info.duration * 9962075.847328244), - "PlayAccess": "Full", - "ProductionYear": albums.info.date, - "RemoteTrailers": [], - "ProviderIds": {}, - "IsFolder": true, - "ParentId": albums.info.albumhash, - "Type": "MusicAlbum", - "People": [], - "Studios": [], - "GenreItems": [], - "LocalTrailerCount": 0, - "UserData": { - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "IsFavorite": albums.info.is_favorite, - "Played": false - }, - "RecursiveItemCount": albums.info.count, - "ChildCount": albums.info.count, - "SpecialFeatureCount": 0, - "DisplayPreferencesId": albums.info.albumhash, - "Tags": [], - "PrimaryImageAspectRatio": 1, - "Artists": albums.info.albumartists.map(artist => artist.name), - "ArtistItems": albums.info.albumartists.map(artist => ({ - "Name": artist.name, - "Id": artist.artisthash - })), - "AlbumArtist": albums.info.albumartists[0].name, - "AlbumArtists": albums.info.albumartists.map(artist => ({ - "Name": artist.name, - "Id": artist.artisthash - })), - "ImageTags": { - "Primary": albums.info.albumhash - }, - "BackdropImageTags": [], - "LocationType": "FileSystem", - "LockedFields": [], - "LockData": false - }); + const items = albums.tracks.map(track => ({ + Album: track.album, + AlbumArtist: track.albumartists[0].name, + AlbumArtists: albums.info.albumartists.map(artist => ({ Id: artist.artisthash, Name: artist.name })), + AlbumId: track.albumhash, + AlbumPrimaryImageTag: track.trackhash, + ArtistItems: track.artists.map(artist => ({ Id: artist.artisthash, Name: artist.name })), + Artists: track.artists.map(artist => artist.name), + BackdropImageTags: [], + ChannelId: null, + ChildCount: 0, + Etag: track.trackhash, + Genres: ["Unknown"], + Id: track.trackhash, + ImageTags: { Primary: track.albumhash }, + IndexNumber: track.track, + IndexNumberEnd: albums.tracks.length, + IsFolder: false, + LocationType: "FileSystem", + MediaType: "Audio", + Name: track.title, + ParentIndexNumber: 1, + ParentPrimaryImageItemId: track.albumhash, + PremiereDate: "2010-02-03T00:00:00.0000000Z", + ProductionYear: albums.info.date, + ProviderIds: {}, + RunTimeTicks: Math.round(track.duration * 9962075.847328244), + ServerId: "server", + SongCount: albums.tracks.length, + Tags: ["Unknown"], + Type: "Audio", + UserData: { PlaybackPositionTicks: 0, PlayCount: 0, IsFavorite: false, Played: false } + })); + + res.json({ + Items: items, + TotalRecordCount: albums.tracks.length, + StartIndex: 0, + Name: albums.info.title, + ServerId: "server", + Id: albums.info.albumhash, + Etag: albums.info.albumhash, + DateCreated: "2024-03-04T00:39:33.730766Z", + CanDelete: true, + CanDownload: false, + SortName: albums.info.title, + PremiereDate: "2010-02-03T00:00:00.0000000Z", + ExternalUrls: [], + Path: "undefined", + EnableMediaSourceDisplay: true, + ChannelId: null, + Taglines: [], + Genres: albums.info.genres, + CumulativeRunTimeTicks: Math.round(albums.info.duration * 9962075.847328244), + RunTimeTicks: Math.round(albums.info.duration * 9962075.847328244), + PlayAccess: "Full", + ProductionYear: albums.info.date, + RemoteTrailers: [], + ProviderIds: {}, + IsFolder: true, + ParentId: albums.info.albumhash, + Type: "MusicAlbum", + People: [], + Studios: [], + GenreItems: [], + LocalTrailerCount: 0, + UserData: { + PlaybackPositionTicks: 0, + PlayCount: 0, + IsFavorite: albums.info.is_favorite, + Played: false + }, + RecursiveItemCount: albums.info.count, + ChildCount: albums.info.count, + SpecialFeatureCount: 0, + DisplayPreferencesId: albums.info.albumhash, + Tags: [], + PrimaryImageAspectRatio: 1, + Artists: albums.info.albumartists.map(artist => artist.name), + ArtistItems: albums.info.albumartists.map(artist => ({ Name: artist.name, Id: artist.artisthash })), + AlbumArtist: albums.info.albumartists[0].name, + AlbumArtists: albums.info.albumartists.map(artist => ({ Name: artist.name, Id: artist.artisthash })), + ImageTags: { Primary: albums.info.albumhash }, + BackdropImageTags: [], + LocationType: "FileSystem", + LockedFields: [], + LockData: false + }); + } catch (err) { + res.json({ + Items: [], + TotalRecordCount: 0, + StartIndex: 0, + ServerId: "server" + }); + } }); -router.route("/:user/favoriteitems/:id") +router.route("/user/favoriteitems/:id") .post(async(req, res) => { const id = req.params.id; @@ -658,23 +759,24 @@ router.route("/:user/favoriteitems/:id") "Content-Type": "application/json" }, body: JSON.stringify({ - "type": type, - "hash": id + type: type, + hash: id }) }); res.json({ - "Rating": 0, - "PlayedPercentage": 0, - "UnplayedItemCount": 0, - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "IsFavorite": true, - "Likes": true, - "LastPlayedDate": "2019-08-24T14:15:22Z", - "Played": true, - "Key": "string", - "ItemId": "string" + Rating: 0, + PlayedPercentage: 0, + UnplayedItemCount: 0, + PlaybackPositionTicks: 0, + PlayCount: 0, + IsFavorite: true, + Likes: true, + LastPlayedDate: "2019-08-24T14:15:22Z", + Played: true, + Key: id, + ItemId: id, + ServerId: "server" }); }) .delete(async(req, res) => { @@ -696,94 +798,27 @@ router.route("/:user/favoriteitems/:id") "Content-Type": "application/json" }, body: JSON.stringify({ - "type": type, - "hash": id + type: type, + hash: id }) }); res.json({ - "Rating": 0, - "PlayedPercentage": 0, - "UnplayedItemCount": 0, - "PlaybackPositionTicks": 0, - "PlayCount": 0, - "IsFavorite": false, - "Likes": true, - "LastPlayedDate": "2019-08-24T14:15:22Z", - "Played": true, - "Key": "string", - "ItemId": "string" + Rating: 0, + PlayedPercentage: 0, + UnplayedItemCount: 0, + PlaybackPositionTicks: 0, + PlayCount: 0, + IsFavorite: false, + Likes: true, + LastPlayedDate: "2019-08-24T14:15:22Z", + Played: true, + Key: id, + ItemId: id, + ServerId: "server" }); }); -router.get("/:id", (req, res) => res.json({ - "Name": "test", - "ServerId": "866914aa47d242e68384ca8a02f9500c", - "Id": "0f8b61481cce4b1ba545f8006eb104c1", - "HasPassword": true, - "HasConfiguredPassword": true, - "HasConfiguredEasyPassword": false, - "EnableAutoLogin": false, - "LastLoginDate": "2024-03-04T15:13:40.4664661Z", - "LastActivityDate": "2024-03-04T15:22:11.1448807Z", - "Configuration": { - "PlayDefaultAudioTrack": true, - "SubtitleLanguagePreference": "", - "DisplayMissingEpisodes": false, - "GroupedFolders": [], - "SubtitleMode": "Default", - "DisplayCollectionsView": false, - "EnableLocalPassword": false, - "OrderedViews": [], - "LatestItemsExcludes": [], - "MyMediaExcludes": [], - "HidePlayedInLatest": true, - "RememberAudioSelections": true, - "RememberSubtitleSelections": true, - "EnableNextEpisodeAutoPlay": true - }, - "Policy": { - "IsAdministrator": true, - "IsHidden": true, - "IsDisabled": false, - "BlockedTags": [], - "EnableUserPreferenceAccess": true, - "AccessSchedules": [], - "BlockUnratedItems": [], - "EnableRemoteControlOfOtherUsers": true, - "EnableSharedDeviceControl": true, - "EnableRemoteAccess": true, - "EnableLiveTvManagement": true, - "EnableLiveTvAccess": true, - "EnableMediaPlayback": true, - "EnableAudioPlaybackTranscoding": true, - "EnableVideoPlaybackTranscoding": true, - "EnablePlaybackRemuxing": true, - "ForceRemoteSourceTranscoding": false, - "EnableContentDeletion": true, - "EnableContentDeletionFromFolders": [], - "EnableContentDownloading": true, - "EnableSyncTranscoding": true, - "EnableMediaConversion": true, - "EnabledDevices": [], - "EnableAllDevices": true, - "EnabledChannels": [], - "EnableAllChannels": true, - "EnabledFolders": [], - "EnableAllFolders": true, - "InvalidLoginAttemptCount": 0, - "LoginAttemptsBeforeLockout": -1, - "MaxActiveSessions": 0, - "EnablePublicSharing": true, - "BlockedMediaFolders": [], - "BlockedChannels": [], - "RemoteClientBitrateLimit": 0, - "AuthenticationProviderId": "Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider", - "PasswordResetProviderId": "Jellyfin.Server.Implementations.Users.DefaultPasswordResetProvider", - "SyncPlayAccess": "CreateAndJoinGroups" - } -})); - module.exports = { router: router, name: "users" diff --git a/router/jellyfin/userviews.js b/router/jellyfin/userviews.js new file mode 100644 index 0000000..5f40d53 --- /dev/null +++ b/router/jellyfin/userviews.js @@ -0,0 +1,60 @@ +const express = require("express"); +const router = express.Router(); + +router.get("/", async(req, res) => { + const folders = await (await fetch(`${global.config.music}/folder`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + "folder": "$home", + "tracks_only": false + }) + })).json(); + + const items = folders.folders.map(folder => ({ + Name: folder.name, + ServerId: "server", + Id: folder.name, + Etag: "tag", + DateCreated: "2024-03-04T00:39:17.500887Z", + CanDelete: false, + CanDownload: false, + SortName: "music", + ExternalUrls: [], + Path: folder.path, + EnableMediaSourceDisplay: true, + ChannelId: null, + Taglines: [], + Genres: [], + RemoteTrailers: [], + ProviderIds: {}, + IsFolder: true, + ParentId: "0", + Type: "CollectionFolder", + People: [], + Studios: [], + GenreItems: [], + LocalTrailerCount: 0, + SpecialFeatureCount: 0, + DisplayPreferencesId: "folder", + Tags: [], + CollectionType: "music", + LocationType: "FileSystem", + LockedFields: [], + LockData: false + })); + + res.json({ + Items: items, + TotalRecordCount: items.length, + StartIndex: 0, + ServerId: "server" + }); +}); + +module.exports = { + router: router, + name: "userviews" +} \ No newline at end of file diff --git a/router/subsonic/createPlaylist.view.js b/router/subsonic/createPlaylist.view.js index f68371d..d6be350 100644 --- a/router/subsonic/createPlaylist.view.js +++ b/router/subsonic/createPlaylist.view.js @@ -18,7 +18,7 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "playlists": { + playlists: { id: playlist.playlist.id, name: playlist.playlist.name, comment: "No comment", @@ -29,8 +29,8 @@ module.exports = async(req, res, proxy, xml) => { created: playlist.playlist.last_updated, coverArt: playlist.playlist.image }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getAlbum.view.js b/router/subsonic/getAlbum.view.js index 491cddb..fecaa0a 100644 --- a/router/subsonic/getAlbum.view.js +++ b/router/subsonic/getAlbum.view.js @@ -12,35 +12,35 @@ module.exports = async(req, res, proxy, xml) => { })).json(); const output = { - "album": { - "id": album.info.albumhash, - "name": album.info.title, - "coverArt": album.info.image, - "songCount": album.info.count, - "created": new Date(album.info.created_date * 1000).toISOString(), - "duration": album.info.duration, - "artist": album.info.albumartists[0].name, - "artistId": album.info.albumartists[0].artisthash, - "song": album.tracks.map(track => { + album: { + id: album.info.albumhash, + name: album.info.title, + coverArt: album.info.image, + songCount: album.info.count, + created: new Date(album.info.created_date * 1000).toISOString(), + duration: album.info.duration, + artist: album.info.albumartists[0].name, + artistId: album.info.albumartists[0].artisthash, + song: album.tracks.map(track => { const song = { - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "album": track.album, - "artist": track.artists[0].name, - "isDir": "false", - "coverArt": track.image, - "created": new Date(album.info.created_date * 1000).toISOString(), - "duration": track.duration, - "bitRate": track.bitrate, - "size": 0, - "suffix": "mp3", - "contentType": "audio/mpeg", - "isVideo": "false", - "path": track.filepath, - "albumId": track.albumhash, - "artistId": track.artists[0].artisthash, - "type": "music" + id: track.trackhash, + parent: track.albumhash, + title: track.title, + album: track.album, + artist: track.artists[0].name, + isDir: "false", + coverArt: track.image, + created: new Date(album.info.created_date * 1000).toISOString(), + duration: track.duration, + bitRate: track.bitrate, + size: 0, + suffix: "mp3", + contentType: "audio/mpeg", + isVideo: "false", + path: track.filepath, + albumId: track.albumhash, + artistId: track.artists[0].artisthash, + type: "music" }; if (track.is_favorite) song.starred = new Date(album.info.created_date * 1000).toISOString(); @@ -55,8 +55,8 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { ...output, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getAlbumList.view.js b/router/subsonic/getAlbumList.view.js index 7392953..3d4f976 100644 --- a/router/subsonic/getAlbumList.view.js +++ b/router/subsonic/getAlbumList.view.js @@ -20,11 +20,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "albumList": { - "album": output + albumList: { + album: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getAlbumList2.view.js b/router/subsonic/getAlbumList2.view.js index 7732952..66196fe 100644 --- a/router/subsonic/getAlbumList2.view.js +++ b/router/subsonic/getAlbumList2.view.js @@ -35,11 +35,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "albumList2": { - "album": output + albumList2: { + album: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getArtist.view.js b/router/subsonic/getArtist.view.js index 564cbf2..abc508f 100644 --- a/router/subsonic/getArtist.view.js +++ b/router/subsonic/getArtist.view.js @@ -19,19 +19,19 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "artist": { - "id": id, - "name": artist.artist.name, - "coverArt": artist.artist.image, - "songCount": artist.artist.trackcount, - "created": new Date(artist.artist.created_date * 1000).toISOString(), - "duration": artist.artist.duration, - "artist": artist.artist.name, - "artistId": id, - "album": albums + artist: { + id: id, + name: artist.artist.name, + coverArt: artist.artist.image, + songCount: artist.artist.trackcount, + created: new Date(artist.artist.created_date * 1000).toISOString(), + duration: artist.artist.duration, + artist: artist.artist.name, + artistId: id, + album: albums }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getArtistInfo.view.js b/router/subsonic/getArtistInfo.view.js index e32ea1a..84724fb 100644 --- a/router/subsonic/getArtistInfo.view.js +++ b/router/subsonic/getArtistInfo.view.js @@ -7,17 +7,17 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "artistInfo": { - "biography": "Unknown", - "musicBrainzId": id, - "lastFmUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "smallImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "mediumImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "largeImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "similarArtist": [] + artistInfo: { + biography: "Unknown", + musicBrainzId: id, + lastFmUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + smallImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + mediumImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + largeImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + similarArtist: [] }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getArtistInfo2.view.js b/router/subsonic/getArtistInfo2.view.js index ff9f4a8..239fd62 100644 --- a/router/subsonic/getArtistInfo2.view.js +++ b/router/subsonic/getArtistInfo2.view.js @@ -7,17 +7,17 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "artistInfo2": { - "biography": "Unknown", - "musicBrainzId": id, - "lastFmUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "smallImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "mediumImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "largeImageUrl": `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, - "similarArtist": [] + artistInfo2: { + biography: "Unknown", + musicBrainzId: id, + lastFmUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + smallImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + mediumImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + largeImageUrl: `${global.config.server.url}/rest/getCoverArt.view?id=${artist.artist.image}`, + similarArtist: [] }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getArtists.view.js b/router/subsonic/getArtists.view.js index 987246f..fec2f00 100644 --- a/router/subsonic/getArtists.view.js +++ b/router/subsonic/getArtists.view.js @@ -26,11 +26,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "artists": { - "index": organizedArtists + artists: { + index: organizedArtists }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getLyrics.view.js b/router/subsonic/getLyrics.view.js index c6633b9..aefb604 100644 --- a/router/subsonic/getLyrics.view.js +++ b/router/subsonic/getLyrics.view.js @@ -41,9 +41,9 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "lyrics": lyrics, - "status": "ok", - "version": "1.16.1" + lyrics: lyrics, + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getMusicFolders.view.js b/router/subsonic/getMusicFolders.view.js index 9d16d45..091a94b 100644 --- a/router/subsonic/getMusicFolders.view.js +++ b/router/subsonic/getMusicFolders.view.js @@ -19,11 +19,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "musicFolders": { - "musicFolder": output + musicFolders: { + musicFolder: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getPlaylist.view.js b/router/subsonic/getPlaylist.view.js index d0f88e0..31b8dd4 100644 --- a/router/subsonic/getPlaylist.view.js +++ b/router/subsonic/getPlaylist.view.js @@ -6,44 +6,44 @@ module.exports = async(req, res, proxy, xml) => { const playlist = await (await fetch(`${global.config.music}/playlist/${id}?no_tracks=false`)).json(); const output = playlist.tracks.map(track => ({ - "id": track.trackhash, - "parent": "655", - "title": track.title, - "album": track.album, - "artist": track.artists[0].name, - "isDir": "false", - "coverArt": track.image, - "created": new Date(track.created_date * 1000).toISOString(), - "duration": track.duration, - "bitRate": track.bitrate, - "track": track.track, - "year": new Date(track.created_date * 1000).getFullYear(), - "size": 0, - "suffix": "mp3", - "contentType": "audio/mpeg", - "isVideo": "false", - "path": track.filepath, - "albumId": track.albumhash, - "artistId": track.artists[0].artisthash, - "type": "music" + id: track.trackhash, + parent: "655", + title: track.title, + album: track.album, + artist: track.artists[0].name, + isDir: "false", + coverArt: track.image, + created: new Date(track.created_date * 1000).toISOString(), + duration: track.duration, + bitRate: track.bitrate, + track: track.track, + year: new Date(track.created_date * 1000).getFullYear(), + size: 0, + suffix: "mp3", + contentType: "audio/mpeg", + isVideo: "false", + path: track.filepath, + albumId: track.albumhash, + artistId: track.artists[0].artisthash, + type: "music" })); const json = { "subsonic-response": { - "playlist": { - "id": playlist.info.id, - "name": playlist.info.name, - "comment": "No comment", - "owner": "admin", - "public": true, - "songCount": playlist.info.count, - "duration": playlist.info.duration, - "created": 0, // 16 hours ago - "coverArt": playlist.info.image, - "entry": output + playlist: { + id: playlist.info.id, + name: playlist.info.name, + comment: "No comment", + owner: "admin", + public: true, + songCount: playlist.info.count, + duration: playlist.info.duration, + created: 0, // 16 hours ago + coverArt: playlist.info.image, + entry: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getPlaylists.view.js b/router/subsonic/getPlaylists.view.js index a8075a5..df22473 100644 --- a/router/subsonic/getPlaylists.view.js +++ b/router/subsonic/getPlaylists.view.js @@ -17,11 +17,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "playlists": { - "playlist": output + playlists: { + playlist: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } }; diff --git a/router/subsonic/getRandomSongs.view.js b/router/subsonic/getRandomSongs.view.js index eac785e..6545f40 100644 --- a/router/subsonic/getRandomSongs.view.js +++ b/router/subsonic/getRandomSongs.view.js @@ -19,21 +19,21 @@ module.exports = async(req, res, proxy, xml) => { })).json(); output.push(...tracks.tracks.map(track => ({ - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "isDir": "false", - "album": track.album, - "artist": track.artists[0].name, - "track": 0, - "year": 2024, - "genre": "Unknown", - "coverArt": track.image, - "size": 0, - "contentType": "audio/mpeg", - "suffix": "mp3", - "duration": track.duration, - "bitRate": track.bitrate + id: track.trackhash, + parent: track.albumhash, + title: track.title, + isDir: "false", + album: track.album, + artist: track.artists[0].name, + track: 0, + year: 2024, + genre: "Unknown", + coverArt: track.image, + size: 0, + contentType: "audio/mpeg", + suffix: "mp3", + duration: track.duration, + bitRate: track.bitrate }))); } @@ -43,11 +43,11 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "randomSongs": { - "song": output + randomSongs: { + song: output }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getScanStatus.view.js b/router/subsonic/getScanStatus.view.js index 5906e31..03e96ca 100644 --- a/router/subsonic/getScanStatus.view.js +++ b/router/subsonic/getScanStatus.view.js @@ -3,12 +3,12 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "scanStatus": { - "scanning": false, - "count": 0 + scanStatus: { + scanning: false, + count: 0 }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getStarred.view.js b/router/subsonic/getStarred.view.js index 12e31d9..9579c5c 100644 --- a/router/subsonic/getStarred.view.js +++ b/router/subsonic/getStarred.view.js @@ -4,56 +4,56 @@ module.exports = async(req, res, proxy, xml) => { const favorites = await (await fetch(`${global.config.music}/favorites`)).json(); const artists = favorites.artists.map(artist => ({ - "name": artist.name, - "id": artist.artisthash, - "starred": new Date(artist.created_date * 1000).toISOString() + name: artist.name, + id: artist.artisthash, + starred: new Date(artist.created_date * 1000).toISOString() })); const albums = favorites.albums.map(album => ({ - "id": album.albumhash, - "parent": album.albumhash, - "title": album.title, - "album": album.title, - "isDir": "true", - "coverArt": album.image, - "created": new Date(album.created_date * 1000).toISOString(), - "starred": new Date(album.created_date * 1000).toISOString() + id: album.albumhash, + parent: album.albumhash, + title: album.title, + album: album.title, + isDir: "true", + coverArt: album.image, + created: new Date(album.created_date * 1000).toISOString(), + starred: new Date(album.created_date * 1000).toISOString() })); const tracks = favorites.tracks.map(track => ({ - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "album": track.album, - "artist": track.artists[0].name, - "isDir": "false", - "coverArt": track.image, - "created": new Date(track.created_date * 1000).toISOString(), - "starred": new Date(track.created_date * 1000).toISOString(), - "duration": track.duration, - "bitRate": track.bitrate, - "track": track.track, - "year": 2024, - "genre": "Unknown", - "size": 0, - "suffix": "mp3", - "contentType": "audio/mpeg", - "isVideo": "false", - "path": track.filepath, - "albumId": track.albumhash, - "artistId": track.artists[0].artisthash, - "type": "music" + id: track.trackhash, + parent: track.albumhash, + title: track.title, + album: track.album, + artist: track.artists[0].name, + isDir: "false", + coverArt: track.image, + created: new Date(track.created_date * 1000).toISOString(), + starred: new Date(track.created_date * 1000).toISOString(), + duration: track.duration, + bitRate: track.bitrate, + track: track.track, + year: 2024, + genre: "Unknown", + size: 0, + suffix: "mp3", + contentType: "audio/mpeg", + isVideo: "false", + path: track.filepath, + albumId: track.albumhash, + artistId: track.artists[0].artisthash, + type: "music" })); const json = { "subsonic-response": { - "starred": { - "artist": artists, - "album": albums, - "song": tracks + starred: { + artist: artists, + album: albums, + song: tracks }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/getStarred2.view.js b/router/subsonic/getStarred2.view.js index 2123d7f..aa8b333 100644 --- a/router/subsonic/getStarred2.view.js +++ b/router/subsonic/getStarred2.view.js @@ -4,59 +4,59 @@ module.exports = async(req, res, proxy, xml) => { const favorites = await (await fetch(`${global.config.music}/favorites`)).json(); const artists = favorites.artists.map(artist => ({ - "id": artist.artisthash, - "name": artist.name, - "coverArt": artist.image, - "albumCount": artist.albumcount, - "starred": new Date(artist.created_date * 1000).toISOString() + id: artist.artisthash, + name: artist.name, + coverArt: artist.image, + albumCount: artist.albumcount, + starred: new Date(artist.created_date * 1000).toISOString() })); const albums = favorites.albums.map(album => ({ - "id": album.albumhash, - "name": album.title, - "artist": album.albumartists[0].artisthash, - "artistId": album.albumartists[0].name, - "coverArt": album.image, - "songCount": album.count, - "duration": album.duration, - "created": new Date(album.created_date * 1000).toISOString(), - "starred": new Date(album.created_date * 1000).toISOString() + id: album.albumhash, + name: album.title, + artist: album.albumartists[0].artisthash, + artistId: album.albumartists[0].name, + coverArt: album.image, + songCount: album.count, + duration: album.duration, + created: new Date(album.created_date * 1000).toISOString(), + starred: new Date(album.created_date * 1000).toISOString() })); const tracks = favorites.tracks.map(track => ({ - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "album": track.album, - "artist": track.artists[0].name, - "isDir": "false", - "coverArt": track.image, - "created": new Date(track.created_date * 1000).toISOString(), - "starred": new Date(track.created_date * 1000).toISOString(), - "duration": track.duration, - "bitRate": track.bitrate, - "track": track.track, - "year": 2024, - "genre": "Unknown", - "size": 0, - "suffix": "mp3", - "contentType": "audio/mpeg", - "isVideo": "false", - "path": track.filepath, - "albumId": track.albumhash, - "artistId": track.artists[0].artisthash, - "type": "music" + id: track.trackhash, + parent: track.albumhash, + title: track.title, + album: track.album, + artist: track.artists[0].name, + isDir: "false", + coverArt: track.image, + created: new Date(track.created_date * 1000).toISOString(), + starred: new Date(track.created_date * 1000).toISOString(), + duration: track.duration, + bitRate: track.bitrate, + track: track.track, + year: 2024, + genre: "Unknown", + size: 0, + suffix: "mp3", + contentType: "audio/mpeg", + isVideo: "false", + path: track.filepath, + albumId: track.albumhash, + artistId: track.artists[0].artisthash, + type: "music" })); const json = { "subsonic-response": { - "starred2": { - "artist": artists, - "album": albums, - "song": tracks + starred2: { + artist: artists, + album: albums, + song: tracks }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/index.js b/router/subsonic/index.js index 0f4549c..8c0dd9d 100644 --- a/router/subsonic/index.js +++ b/router/subsonic/index.js @@ -32,8 +32,8 @@ function checkAuth(req, res, next) { const json = { "subsonic-response": { - "status": "unauthorized", - "version": "1.16.1" + status: "unauthorized", + version: "1.16.1" } } @@ -80,8 +80,8 @@ module.exports = async(app) => { const json = { "subsonic-response": { - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/search2.view.js b/router/subsonic/search2.view.js index 361200c..5c3fe16 100644 --- a/router/subsonic/search2.view.js +++ b/router/subsonic/search2.view.js @@ -8,8 +8,8 @@ module.exports = async(req, res, proxy, xml) => { if (artistCount >= 1) { artists = await (await fetch(`${global.config.music}/search/artists?q=${query}`)).json(); artists = artists.artists.map(artist => ({ - "id": artist.artisthash, - "name": artist.name + id: artist.artisthash, + name: artist.name })); } @@ -18,12 +18,12 @@ module.exports = async(req, res, proxy, xml) => { if (albumCount >= 1) { albums = await (await fetch(`${global.config.music}/search/albums?q=${query}`)).json(); albums = albums.albums.map(album => ({ - "id": album.albumhash, - "parent": album.albumhash, - "title": album.title, - "artist": album.albumartists[0].name, - "isDir": "true", - "coverArt": album.image + id: album.albumhash, + parent: album.albumhash, + title: album.title, + artist: album.albumartists[0].name, + isDir: "true", + coverArt: album.image })); } @@ -32,32 +32,32 @@ module.exports = async(req, res, proxy, xml) => { if (songCount >= 1) { tracks = await (await fetch(`${global.config.music}/search/tracks?q=${query}`)).json(); tracks = tracks.tracks.map(track => ({ - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "isDir": "false", - "album": track.album, - "artist": track.albumartists[0].name, - "track": 0, - "year": 2024, - "genre": "Unknown", - "coverArt": track.image, - "size": 0, - "contentType": "audio/mpeg", - "suffix": "mp3", - "isVideo": "false" + id: track.trackhash, + parent: track.albumhash, + title: track.title, + isDir: "false", + album: track.album, + artist: track.albumartists[0].name, + track: 0, + year: 2024, + genre: "Unknown", + coverArt: track.image, + size: 0, + contentType: "audio/mpeg", + suffix: "mp3", + isVideo: "false" })); } const json = { "subsonic-response": { - "searchResult2": { - "artist": artists, - "album": albums, - "song": tracks + searchResult2: { + artist: artists, + album: albums, + song: tracks }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/search3.view.js b/router/subsonic/search3.view.js index 71202b7..4e83919 100644 --- a/router/subsonic/search3.view.js +++ b/router/subsonic/search3.view.js @@ -8,10 +8,10 @@ module.exports = async(req, res, proxy, xml) => { if (artistCount >= 1) { artists = await (await fetch(`${global.config.music}/search/artists?q=${query}`)).json(); artists = artists.artists.map(artist => ({ - "id": artist.artisthash, - "name": artist.name, - "coverArt": artist.image, - "albumCount": artist.albumcount + id: artist.artisthash, + name: artist.name, + coverArt: artist.image, + albumCount: artist.albumcount })); } @@ -20,14 +20,14 @@ module.exports = async(req, res, proxy, xml) => { if (albumCount >= 1) { albums = await (await fetch(`${global.config.music}/search/albums?q=${query}`)).json(); albums = albums.albums.map(album => ({ - "id": album.albumhash, - "name": album.title, - "coverArt": album.image, - "songCount": 0, - "created": new Date(album.created_date * 1000).toISOString(), - "duration": 0, - "artist": album.albumartists[0].name, - "artistId": album.albumartists[0].artisthash + id: album.albumhash, + name: album.title, + coverArt: album.image, + songCount: 0, + created: new Date(album.created_date * 1000).toISOString(), + duration: 0, + artist: album.albumartists[0].name, + artistId: album.albumartists[0].artisthash })); } @@ -36,39 +36,39 @@ module.exports = async(req, res, proxy, xml) => { if (songCount >= 1) { tracks = await (await fetch(`${global.config.music}/search/tracks?q=${query}`)).json(); tracks = tracks.tracks.map(track => ({ - "id": track.trackhash, - "parent": track.albumhash, - "title": track.title, - "album": track.album, - "artist": track.albumartists[0].name, - "isDir": "false", - "coverArt": track.image, - "created": "2007-03-15T06:46:06", - "duration": track.duration, - "bitRate": track.bitrate, - "track": 0, - "year": 2024, - "genre": "Unknown", - "size": 0, - "suffix": "mp3", - "contentType": "audio/mpeg", - "isVideo": "false", - "path": track.filepath, - "albumId": track.albumhash, - "artistId": track.albumartists[0].artisthash, - "type": "music" + id: track.trackhash, + parent: track.albumhash, + title: track.title, + album: track.album, + artist: track.albumartists[0].name, + isDir: "false", + coverArt: track.image, + created: "2007-03-15T06:46:06", + duration: track.duration, + bitRate: track.bitrate, + track: 0, + year: 2024, + genre: "Unknown", + size: 0, + suffix: "mp3", + contentType: "audio/mpeg", + isVideo: "false", + path: track.filepath, + albumId: track.albumhash, + artistId: track.albumartists[0].artisthash, + type: "music" })); } const json = { "subsonic-response": { - "searchResult3": { - "artist": artists, - "album": albums, - "song": tracks + searchResult3: { + artist: artists, + album: albums, + song: tracks }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/star.view.js b/router/subsonic/star.view.js index eaae5bd..4ce717d 100644 --- a/router/subsonic/star.view.js +++ b/router/subsonic/star.view.js @@ -15,8 +15,8 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/startScan.view.js b/router/subsonic/startScan.view.js index f4e4764..d75f458 100644 --- a/router/subsonic/startScan.view.js +++ b/router/subsonic/startScan.view.js @@ -14,12 +14,12 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "scanStatus": { - "scanning": status, - "count": tracks?.folders[0]?.count || 0 + scanStatus: { + scanning: status, + count: tracks?.folders[0]?.count || 0 }, - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/unstar.view.js b/router/subsonic/unstar.view.js index c8f8fb8..4d71630 100644 --- a/router/subsonic/unstar.view.js +++ b/router/subsonic/unstar.view.js @@ -15,8 +15,8 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } } diff --git a/router/subsonic/updatePlaylist.view.js b/router/subsonic/updatePlaylist.view.js index b49f894..f97fdb8 100644 --- a/router/subsonic/updatePlaylist.view.js +++ b/router/subsonic/updatePlaylist.view.js @@ -34,8 +34,8 @@ module.exports = async(req, res, proxy, xml) => { const json = { "subsonic-response": { - "status": "ok", - "version": "1.16.1" + status: "ok", + version: "1.16.1" } }