diff --git a/disabled/etyd.js b/disabled/etyd.js deleted file mode 100644 index 17e2834..0000000 --- a/disabled/etyd.js +++ /dev/null @@ -1,122 +0,0 @@ -import { app, globalConfig } from "../index.js" // Get globals from index -import { checkToken } from "../liberals/auth.js" -import { logRequest } from "../liberals/logging.js" - -app.get("/api/etyd*", (rreq,rres) => { - fetch(`${globalConfig.couchdbHost}/etyd${rreq.path.replace("/api/etyd","")}`).then(dbRes => { - if (dbRes.status == 404) { - rres.sendStatus(404) - } else { - dbRes.json().then(dbRes => { - try { - rres.redirect(dbRes.content.url) // Node will crash if the Database entry is malformed - } catch (responseError) { - logRequest(rres,rreq,500,responseError) - rres.sendStatus(500) - } - }) - } - }).catch(fetchError => { - logRequest(rres,rreq,500,fetchError) - rres.sendStatus(500) - }) -}) - -app.delete("/api/etyd*", (rreq,rres) => { - - if (rreq.get("Authorization") === undefined) { - rres.sendStatus(400) - } else { - checkToken(rreq.get("Authorization"),"etyd").then(authRes => { - if (authRes === false) { - rres.sendStatus(401) - } else if (authRes === true) { // Authorization successful - - fetch(`${globalConfig.couchdbHost}/etyd${rreq.path.replace("/api/etyd", "")}`).then(dbRes => { - - if (dbRes.status == 404) { - rres.sendStatus(404) // Entry does not exist - } else { - dbRes.json().then(dbRes => { - - fetch(`${globalConfig.couchdbHost}/etyd${rreq.path.replace("/api/etyd", "")}`, { - method: "DELETE", - headers: { - "If-Match": dbRes["_rev"] // Using the If-Match header is easiest for deleting entries in couchdb - } - }).then(fetchRes => { - if (fetchRes.status == 200) { - // console.log(`${rres.get("cf-connecting-ip")} DELETE ${rreq.path} returned 200 KEY: ${rreq.get("Authorization")}`) - logRequest(rres,rreq,200) - rres.sendStatus(200) - } - }).catch(fetchError => { - // console.log(`${rres.get("cf-connecting-ip")} DELETE ${rreq.path} returned 500: ${fetchError}`) - logRequest(rres,rreq,500,fetchError) - rres.sendStatus(500) - }) - - }) - } - - }).catch(fetchError => { - logRequest(rres,rreq,500,fetchError) - rres.sendStatus(500) - }) - - } - }) - } - -}) - -app.post("/api/etyd*", (rreq,rres) => { - - if (rreq.get("Authorization") === undefined) { - rres.sendStatus(400) - } else { - checkToken(rreq.get("Authorization"),"etyd").then(authRes => { - if (authRes === false) { - rres.sendStatus(401) - } else if (authRes === true) { // Authorization successful - - if (rreq.body["url"] == undefined) { - rres.sendStatus(400) - } else { - fetch(`${globalConfig.couchdbHost}/etyd${rreq.path.replace("/api/etyd", "")}`, { - method: "PUT", - body: JSON.stringify({ - "content": { - "url": rreq.body["url"] - } - }) - }).then(dbRes => { - - switch(dbRes.status) { - case 409: - rres.sendStatus(409) - break; - - case 201: - rres.status(200).send(rreq.path.replace("/api/etyd", "")) - break; - - default: - logRequest(rres,rreq,500,`CouchDB PUT did not return expected code: ${dbRes.status}`) - rres.sendStatus(500) - break; - } - - }).catch(fetchError => { - logRequest(rres,rreq,500,fetchError) - rres.sendStatus(500) - }) - } - - } - }) - } - -}) - -export {app} // export routes to be imported by index for execution \ No newline at end of file diff --git a/index.js b/index.js index 082c881..43c7b93 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ const globalConfig = await fetch(`${process.env.API_DBHOST}/config/${process.env }) const globalVersion = execSync(`git show --oneline -s`).toString().split(" ")[0] -export { app, fs, globalConfig, globalVersion} +export { app, fs, globalConfig, globalVersion } app.use(json()) // Allows receiving JSON bodies // see important note: https://expressjs.com/en/api.html#express.json diff --git a/liberals/auth.js b/liberals/auth.js index e297c2e..171db72 100644 --- a/liberals/auth.js +++ b/liberals/auth.js @@ -7,7 +7,9 @@ import { globalConfig } from "../index.js" * @returns True for successful authentication and authorization, false if either fail */ async function checkToken(token,scope) { - return await fetch(`${globalConfig.couchdbHost}/auth/sessions`).then(fetchRes => { + return await fetch(`${process.env.API_DBHOST}/auth/sessions`, { + headers: { "Authorization": `Basic ${btoa(process.env.API_DBCRED)}`} + }).then(fetchRes => { return fetchRes.json().then(dbRes => { diff --git a/liberals/libnowplaying.js b/liberals/libnowplaying.js index a0609e5..5ef7e92 100644 --- a/liberals/libnowplaying.js +++ b/liberals/libnowplaying.js @@ -1,16 +1,23 @@ import { globalConfig } from "../index.js" +const notPlayingAnythingPlaceholder = { + "json": { + "playing": false + }, + "html": `I'm not currently listening to anything.` +} + /** * Queries LastFM for user set in config file and returns formatted result - * @returns {object} Object containing response in JSON and HTML (as string), WILL RETURN EMPTY OBJECT ON FAILURE! + * @returns {object} Object containing response in JSON and HTML (as string) */ async function queryLastfm() { return await fetch(`https://ws.audioscrobbler.com/2.0/?format=json&method=user.getrecenttracks&limit=1&api_key=${globalConfig.nowplaying.lastfm.apiKey}&user=${globalConfig.nowplaying.lastfm.target}`).then(response => response.json()).then(response => { if (response["recenttracks"] == undefined) { - return {} + return notPlayingAnythingPlaceholder } else { if (response.recenttracks.track[0]["@attr"] == undefined) { - return {} + return notPlayingAnythingPlaceholder } else { return { "json": { @@ -30,17 +37,29 @@ async function queryLastfm() { }) } -// async function queryJellyfin() { -// return await fetch(`${globalConfig.nowplaying.jellyfin.host}/Sessions`, { -// headers: { -// "Authorization": `MediaBrowser Token=${globalConfig.nowplaying.jellyfin.apiKey}` -// } -// }).then(response => response.json()).then(response => { -// for (x in response) { -// if (response[x].UserName !== globalConfig.nowplaying.jellyfin.target) { break } -// if (response[x].) -// } -// }) -// } +async function queryJellyfin() { + return await fetch(`${globalConfig.nowplaying.jellyfin.host}/Sessions`, { + headers: { + "Authorization": `MediaBrowser Token=${globalConfig.nowplaying.jellyfin.apiKey}` + } + }).then(response => response.json()).then(response => { + for (x in response) { + if (response[x].UserName !== globalConfig.nowplaying.jellyfin.target) { break } // If session does not belong to target specified in config, skip + if (!response[x].NowPlayingItem) { break } // If the NowPlayingItem object is not present, skip (session is not playing anything) + if (response[x].NowPlayingItem.MediaType !== "Audio") { break } // If not playing 'audio', skip, this might change in the future + + return { + "json": { + "songName": response[x].NowPlayingItem.Name, + "artistName": response[x].NowPlayingItem.Artists[0], + "albumName": response.recenttracks.track[0].album["#text"], + "artUrl": response.recenttracks.track[0].image[3]["#text"], + "link": response.recenttracks.track[0].url + }, + "html": `Album Art

I'm listening to

${response.recenttracks.track[0].name} by ${response.recenttracks.track[0].artist["#text"]}

from ${response.recenttracks.track[0].album["#text"]}

View on Last.fm
` + } + } + }) +} export { queryLastfm } \ No newline at end of file diff --git a/liberals/logging.js b/liberals/logging.js index 01d2606..3586855 100644 --- a/liberals/logging.js +++ b/liberals/logging.js @@ -6,21 +6,7 @@ * @param {string} extra Optional extra details to add to log, ideal for caught errors */ function logRequest(response,request,code,extra) { - if (extra) { - actualExtra = "; Extra: "+extra - } else { - actualExtra = "" - } - if (request.get("Authorization")) { - actualAuth = `(${request.get("Authorization")})` - } else { - actualAuth = "" - } - // Client IP if connecting over Cloudflare, else IP as received by Express - // | / Token used (if provided) - // | / | Request Method Request Path Status code returned to client provided by function call - // V V V V V V Extra information if provided by function call - console.log(`${request.get("cf-connecting-ip") ?? request.ip}${actualAuth}${request.method} ${request.path} returned ${code}${actualExtra}`) + console.log(`${request.get("cf-connecting-ip") ?? request.ip} ${request.get("Authorization") ?? ""} ${request.method} ${request.path} returned ${code} ${extra ?? ""}`) } export { logRequest } \ No newline at end of file diff --git a/routes/etyd.js b/routes/etyd.js new file mode 100644 index 0000000..f185745 --- /dev/null +++ b/routes/etyd.js @@ -0,0 +1,130 @@ +import { app, globalConfig } from "../index.js" // Get globals from index +import { checkToken } from "../liberals/auth.js" +import { logRequest } from "../liberals/logging.js" + +app.get("/api/etyd*", (rreq,rres) => { + fetch(`${process.env.API_DBHOST}/etyd${rreq.path.replace("/api/etyd","")}`,{ + headers: { "Authorization": `Basic ${btoa(process.env.API_DBCRED)}`} + }).then(dbRes => { + if (dbRes.status == 404) { + rres.sendStatus(404) + } else { + dbRes.json().then(dbRes => { + try { + rres.redirect(dbRes.content.url) // Node will crash if the Database entry is malformed + } catch (responseError) { + logRequest(rres,rreq,500,responseError) + rres.sendStatus(500) + } + }) + } + }).catch(fetchError => { + logRequest(rres,rreq,500,fetchError) + rres.sendStatus(500) + }) +}) + +// app.delete("/api/etyd*", (rreq,rres) => { + +// if (rreq.get("Authorization") === undefined) { +// rres.sendStatus(400) +// } else { +// checkToken(rreq.get("Authorization"),"etyd").then(authRes => { +// if (authRes === false) { +// rres.sendStatus(401) +// } else if (authRes === true) { // Authorization successful + +// fetch(`${process.env.API_DBHOST}/etyd${rreq.path.replace("/api/etyd", "")}`,{ +// headers: { "Authorization": `Basic ${btoa(process.env.API_DBCRED)}`} +// }).then(dbRes => { + +// if (dbRes.status == 404) { +// rres.sendStatus(404) // Entry does not exist +// } else { +// dbRes.json().then(dbRes => { + +// fetch(`${process.env.API_DBHOST}/etyd${rreq.path.replace("/api/etyd", ""),{ +// headers: { "Authorization": `Basic ${btoa(process.env.API_DBCRED)}`} +// }}`, { +// method: "DELETE", +// headers: { +// "If-Match": dbRes["_rev"] // Using the If-Match header is easiest for deleting entries in couchdb +// } +// }).then(fetchRes => { +// if (fetchRes.status == 200) { +// // console.log(`${rres.get("cf-connecting-ip")} DELETE ${rreq.path} returned 200 KEY: ${rreq.get("Authorization")}`) +// logRequest(rres,rreq,200) +// rres.sendStatus(200) +// } +// }).catch(fetchError => { +// // console.log(`${rres.get("cf-connecting-ip")} DELETE ${rreq.path} returned 500: ${fetchError}`) +// logRequest(rres,rreq,500,fetchError) +// rres.sendStatus(500) +// }) + +// }) +// } + +// }).catch(fetchError => { +// logRequest(rres,rreq,500,fetchError) +// rres.sendStatus(500) +// }) + +// } +// }) +// } + +// }) + +// app.post("/api/etyd*", (rreq,rres) => { + +// if (rreq.get("Authorization") === undefined) { +// rres.sendStatus(400) +// } else { +// checkToken(rreq.get("Authorization"),"etyd").then(authRes => { +// if (authRes === false) { +// rres.sendStatus(401) +// } else if (authRes === true) { // Authorization successful + +// if (rreq.body["url"] == undefined) { +// rres.sendStatus(400) +// } else { +// fetch(`${process.env.API_DBHOST}/etyd${rreq.path.replace("/api/etyd", ""),{ +// headers: { "Authorization": `Basic ${btoa(process.env.API_DBCRED)}`} +// }}`, { +// method: "PUT", +// body: JSON.stringify({ +// "content": { +// "url": rreq.body["url"] +// } +// }) +// }).then(dbRes => { + +// switch(dbRes.status) { +// case 409: +// rres.sendStatus(409) +// break; + +// case 201: +// rres.status(200).send(rreq.path.replace("/api/etyd", "")) +// break; + +// default: +// logRequest(rres,rreq,500,`CouchDB PUT did not return expected code: ${dbRes.status} ${dbRes.statusText}`) +// rres.sendStatus(500) +// break; +// } + +// }).catch(fetchError => { +// logRequest(rres,rreq,500,fetchError) +// rres.sendStatus(500) +// }) +// } + +// } +// }) +// } + +// }) + +export {app} // export routes to be imported by index for execution \ No newline at end of file diff --git a/disabled/nowplaying.js b/routes/nowplaying.js similarity index 83% rename from disabled/nowplaying.js rename to routes/nowplaying.js index 7acd304..29b8958 100644 --- a/disabled/nowplaying.js +++ b/routes/nowplaying.js @@ -4,13 +4,6 @@ import { queryLastfm } from "../liberals/libnowplaying.js" var timeSinceLastLastfmQuery = Date.now()-5000 var cachedLastfmResult = {} -const notPlayingAnythingPlaceholder = { - "json": { - "playing": false - }, - "html": `I'm not currently listening to anything.` -} - app.get("/api/nowplaying", (rreq,rres) => { if (Date.now() < timeSinceLastLastfmQuery+5000) {