var Clay = require('@rebble/clay'); var clayConfig = require('./config'); var keys = require('message_keys'); new Clay(clayConfig); var cfg = JSON.parse(localStorage.getItem('clay-settings')); var lookupMap = new Map(); Pebble.addEventListener("ready", function () { // store cache of library info from Jellyfin if (cfg.PRIV_BASE_URL && cfg.PRIV_API_KEY && cfg.PRIV_USERNAME) { // get userId from Jellyfin callAPI("GET", cfg.PRIV_BASE_URL + "/Users", function (userIdResp) { if (userIdResp === null) { return; } const userIdObj = JSON.parse(userIdResp); let userId; for (const user of userIdObj) { if (user.Name === cfg.PRIV_USERNAME) { userId = user.Id; break; } } // get library response from Jellyfin callAPI("GET", cfg.PRIV_BASE_URL + "/Items?userId=" + userId + "&recursive=true&includeItemTypes=Audio&sortBy=AlbumArtist,Artist,ProductionYear,Album,IndexNumber,Name", function (libResp) { if (libResp === null) return; const libObj = JSON.parse(libResp); // format response for jellyPod //// build lookupMap let lastAlbumInfo = {AlbumArtist: "", AlbumName: "", AlbumYear: 0}; for (const track of libObj.Items) { if (!track.Name) continue; let albumArtist = "unknown artist"; if (track.AlbumArtist) { albumArtist = track.AlbumArtist; } else if (track.Artists.length > 0) { albumArtist = track.Artists[0]; } const albumName = track.Album ? track.Album : "unknown album"; // insert every track into lookupMap const firstChar = Array.from(albumArtist)[0].toUpperCase(); if (!lookupMap.has(firstChar)) { lookupMap.set(firstChar, new Map()); } const artistToAlbumsMap = lookupMap.get(firstChar); if (!artistToAlbumsMap.has(albumArtist)) { artistToAlbumsMap.set(albumArtist, new Map()); } const albumToTracksMap = artistToAlbumsMap.get(albumArtist); if (!albumToTracksMap.has(albumName)) { albumToTracksMap.set(albumName, []); } albumToTracksMap.get(albumName).push({ TrackName: track.Name, JfId: track.Id }); // consider the album to have changed if the album name OR artist changed if (lastAlbumInfo.AlbumArtist !== albumArtist || lastAlbumInfo.AlbumName !== albumName) { lastAlbumInfo = { AlbumArtist: albumArtist, AlbumName: albumName, AlbumYear: track.ProductionYear ? track.ProductionYear : 1970 }; } } //console.log(JSON.stringify(lookupMap, (k, v) => v instanceof Map ? Object.fromEntries(v) : v)); const readyDict = {}; readyDict[keys.PKJS_READY] = 1; Pebble.sendAppMessage(readyDict); }); }); } }); Pebble.addEventListener("appmessage", function (dict) { if (dict.payload[keys.OUT_MENU_NAV_SCOPE]) { switch (dict.payload[keys.OUT_MENU_NAV_SCOPE]) { case 1: { // search const vanityList = Array.from(lookupMap.keys()); const outDict = {}; for (let i = 0; i < vanityList.length; i++) { outDict[keys.IN_VANITY_LIST + i] = vanityList[i]; } Pebble.sendAppMessage(outDict); return; } default: return; } } }); function reportAPIFailure() { console.log("API FAILURE"); } function callAPI(method, endpoint, callback) { const xhr = new XMLHttpRequest(); xhr.onload = function () { switch (xhr.status) { case 200: callback(this.responseText); return; default: reportAPIFailure(); } }; xhr.onerror = function () { reportAPIFailure(); }; xhr.ontimeout = function () { reportAPIFailure(); }; xhr.open(method, endpoint, true); xhr.timeout = 8000; xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Authorization", 'MediaBrowser Token="' + cfg.PRIV_API_KEY + '"'); xhr.send(); } // On Settings Save/Sync Button Press //// Get User ID //curl -H "Authorization: MediaBrowser Token=\"TOKEN\"" -X GET 'BASEURL/Users' // Get Track List Using Logic From JellyPod Server // On Every Startup //// Get Session ID //curl -H "Authorization: MediaBrowser Token=\"TOKEN\"" -X GET 'BASEURL/Sessions' // Filter by: // UserId // Sort by: // LastActivityDate // Controls //// Select Track (pass through a queue) //curl - H "Authorization: MediaBrowser Token=\"TOKEN\"" - X POST 'BASEURL/Sessions/SESSIONID/Playing?playCommand=PlayNow&itemIds=XXX,YYY'