Initial commit
This commit is contained in:
67
src/index.html
Normal file
67
src/index.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-gb">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MuonRC</title>
|
||||
<link rel="stylesheet" href="res/normalise.min.css">
|
||||
<link rel="stylesheet" href="res/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="hr"></div>
|
||||
<h1 style="margin: 5px 0 0 0;">MuonRC</h1>
|
||||
<sub>v0.1.0 - "a grand don't come for free" Edition</sub>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#details">Details</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#status">Status</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#playback">Playback</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<section id="details">
|
||||
<h2>Server Details</h2>
|
||||
<div class="flex-row">
|
||||
<div>
|
||||
<label for="host">Host</label>
|
||||
<br>
|
||||
<input type="text" name="host" id="host" placeholder="localhost">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="details-submit">Submit</button>
|
||||
<button id="details-clear">Clear</button>
|
||||
<p class="success" id="details-success">Connected successfully!</p>
|
||||
<p class="error" id="details-error">Can't connect to specified hostname!</p>
|
||||
</section>
|
||||
<section id="status">
|
||||
<h2>Status</h2>
|
||||
<p>API Version: <span id="api-version"></span></p>
|
||||
</section>
|
||||
<section id="playback">
|
||||
<h2>Playback</h2>
|
||||
<div id="player">
|
||||
<img src="" alt="Album art" id="album-art">
|
||||
<p id="playback-song"></p>
|
||||
<p id="playback-album"></p>
|
||||
<p id="playback-artist"></p>
|
||||
<div id="controls">
|
||||
<input id="controls-play" type="image" src="res/img/play.svg" alt="Play">
|
||||
<input id="controls-stop" type="image" src="res/img/stop.svg" alt="Stop">
|
||||
<input id="controls-rewind" type="image" src="res/img/rewind.svg" alt="Last song">
|
||||
<input id="controls-fastforward" type="image" src="res/img/fastforward.svg" alt="Next song">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<script type="module" src="res/muonrc.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1
src/res/img/fastforward.svg
Normal file
1
src/res/img/fastforward.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M100-240v-480l360 240-360 240Zm400 0v-480l360 240-360 240ZM180-480Zm400 0Zm-400 90 136-90-136-90v180Zm400 0 136-90-136-90v180Z"/></svg>
|
||||
|
After Width: | Height: | Size: 251 B |
1
src/res/img/play.svg
Normal file
1
src/res/img/play.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M320-200v-560l440 280-440 280Zm80-280Zm0 134 210-134-210-134v268Z"/></svg>
|
||||
|
After Width: | Height: | Size: 190 B |
1
src/res/img/rewind.svg
Normal file
1
src/res/img/rewind.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M860-240 500-480l360-240v480Zm-400 0L100-480l360-240v480Zm-80-240Zm400 0Zm-400 90v-180l-136 90 136 90Zm400 0v-180l-136 90 136 90Z"/></svg>
|
||||
|
After Width: | Height: | Size: 254 B |
1
src/res/img/stop.svg
Normal file
1
src/res/img/stop.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M320-640v320-320Zm-80 400v-480h480v480H240Zm80-80h320v-320H320v320Z"/></svg>
|
||||
|
After Width: | Height: | Size: 192 B |
159
src/res/muonrc.ts
Normal file
159
src/res/muonrc.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { version, status, pic, play, pause, back, next } from "./routes.js"
|
||||
|
||||
interface sectionObj {
|
||||
element: HTMLElement,
|
||||
name: string
|
||||
}
|
||||
|
||||
const sections: Array<sectionObj> = [
|
||||
{
|
||||
element: document.getElementById("details")!,
|
||||
name: "details"
|
||||
},
|
||||
{
|
||||
element: document.getElementById("status")!,
|
||||
name: "status"
|
||||
},
|
||||
{
|
||||
element: document.getElementById("playback")!,
|
||||
name: "playback"
|
||||
}
|
||||
]
|
||||
|
||||
function updatePlayback(host: string) {
|
||||
const art = document.getElementById("album-art") as HTMLImageElement
|
||||
if (host === null) {
|
||||
console.error("no host set!")
|
||||
return
|
||||
}
|
||||
status(host)
|
||||
.then(stat => {
|
||||
document.getElementById("playback-song")!.innerText = stat.title
|
||||
document.getElementById("playback-album")!.innerText = stat.album
|
||||
document.getElementById("playback-artist")!.innerText = stat.artist
|
||||
pic(host, stat.id, "medium")
|
||||
.then(blob => {
|
||||
art.src = URL.createObjectURL(blob)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function showView(sectionName: string) {
|
||||
for (const section of sections) {
|
||||
if (section.name === sectionName)
|
||||
section.element.style.display = "block"
|
||||
else
|
||||
section.element.style.display = "none"
|
||||
}
|
||||
|
||||
const cachedHost = localStorage.getItem("host")
|
||||
switch (sectionName) {
|
||||
case "status":
|
||||
if (cachedHost === null) {
|
||||
document.getElementById("api-version")!.innerText = "No host set!"
|
||||
return
|
||||
}
|
||||
|
||||
version(cachedHost)
|
||||
.then(res => res.version)
|
||||
.then(ver => document.getElementById("api-version")!.innerText = `${ver}`)
|
||||
|
||||
break
|
||||
case "playback":
|
||||
updatePlayback(cachedHost!)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function setupDefaultDetails() {
|
||||
const host = document.getElementById("host") as HTMLInputElement
|
||||
const cachedHost = localStorage.getItem("host")
|
||||
if (cachedHost !== null) {
|
||||
host.placeholder = cachedHost
|
||||
host.disabled = true
|
||||
} else {
|
||||
host.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
setupDefaultDetails()
|
||||
if (window.location.hash !== "#details" && localStorage.getItem("host") === null)
|
||||
window.location.hash = "#details"
|
||||
else {
|
||||
showView(window.location.hash.substring(1))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addEventListener("hashchange", (e) => {
|
||||
const newURL = new URL(e.newURL)
|
||||
showView(newURL.hash.substring(1))
|
||||
})
|
||||
|
||||
function showDetailsErr() {
|
||||
const error = document.getElementById("details-error") as HTMLParagraphElement
|
||||
error.style.display = "block"
|
||||
setTimeout(() => {
|
||||
error.style.display = "none"
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
function showDetailsSuccess() {
|
||||
const success = document.getElementById("details-success") as HTMLParagraphElement
|
||||
success.style.display = "block"
|
||||
setTimeout(() => {
|
||||
success.style.display = "none"
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
document.getElementById("details-submit")!.addEventListener("click", () => {
|
||||
const host = document.getElementById("host") as HTMLInputElement
|
||||
console.log(host)
|
||||
if (host.value === "")
|
||||
return
|
||||
localStorage.setItem("host", host.value)
|
||||
|
||||
version(host.value)
|
||||
.then(() => {
|
||||
console.log("success! saved")
|
||||
host.disabled = true
|
||||
showDetailsSuccess()
|
||||
})
|
||||
.catch(() => {
|
||||
localStorage.removeItem("host")
|
||||
host.disabled = false
|
||||
showDetailsErr()
|
||||
})
|
||||
})
|
||||
|
||||
document.getElementById("details-clear")!.addEventListener("click", () => {
|
||||
localStorage.removeItem("host")
|
||||
setupDefaultDetails()
|
||||
})
|
||||
|
||||
document.getElementById("controls-play")!.addEventListener("click", () => {
|
||||
play(localStorage.getItem("host")!)
|
||||
})
|
||||
|
||||
document.getElementById("controls-stop")!.addEventListener("click", () => {
|
||||
pause(localStorage.getItem("host")!)
|
||||
})
|
||||
|
||||
document.getElementById("controls-rewind")!.addEventListener("click", () => {
|
||||
const host = localStorage.getItem("host")
|
||||
next(host!)
|
||||
setTimeout(() => {
|
||||
updatePlayback(host!)
|
||||
}, 50);
|
||||
})
|
||||
|
||||
document.getElementById("controls-fastforward")!.addEventListener("click", () => {
|
||||
const host = localStorage.getItem("host")!
|
||||
back(host!)
|
||||
setTimeout(() => {
|
||||
updatePlayback(host!)
|
||||
}, 50);
|
||||
})
|
||||
|
||||
main()
|
||||
2
src/res/normalise.min.css
vendored
Normal file
2
src/res/normalise.min.css
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
|
||||
/*# sourceMappingURL=normalize.min.css.map */
|
||||
1
src/res/normalize.min.css.map
Normal file
1
src/res/normalize.min.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["normalize.min.css"],"names":[],"mappings":"AAAA,4EAUA,KACE,YAAa,KACb,yBAA0B,KAU5B,KACE,OAAQ,EAOV,KACE,QAAS,MAQX,GACE,UAAW,IACX,OAAQ,MAAO,EAWjB,GACE,WAAY,YACZ,OAAQ,EACR,SAAU,QAQZ,IACE,YAAa,SAAS,CAAE,UACxB,UAAW,IAUb,EACE,iBAAkB,YAQpB,YACE,cAAe,KACf,gBAAiB,UACjB,gBAAiB,UAAU,OAO7B,EACA,OACE,YAAa,OAQf,KACA,IACA,KACE,YAAa,SAAS,CAAE,UACxB,UAAW,IAOb,MACE,UAAW,IAQb,IACA,IACE,UAAW,IACX,YAAa,EACb,SAAU,SACV,eAAgB,SAGlB,IACE,OAAQ,OAGV,IACE,IAAK,MAUP,IACE,aAAc,KAWhB,OACA,MACA,SACA,OACA,SACE,YAAa,QACb,UAAW,KACX,YAAa,KACb,OAAQ,EAQV,OACA,MACE,SAAU,QAQZ,OACA,OACE,eAAgB,KAQlB,cACA,aACA,cAHA,OAIE,mBAAoB,OAQtB,gCACA,+BACA,gCAHA,yBAIE,aAAc,KACd,QAAS,EAQX,6BACA,4BACA,6BAHA,sBAIE,QAAS,IAAI,OAAO,WAOtB,SACE,QAAS,MAAO,MAAO,OAUzB,OACE,WAAY,WACZ,MAAO,QACP,QAAS,MACT,UAAW,KACX,QAAS,EACT,YAAa,OAOf,SACE,eAAgB,SAOlB,SACE,SAAU,KAQZ,gBACA,aACE,WAAY,WACZ,QAAS,EAOX,yCACA,yCACE,OAAQ,KAQV,cACE,mBAAoB,UACpB,eAAgB,KAOlB,yCACE,mBAAoB,KAQtB,6BACE,mBAAoB,OACpB,KAAM,QAUR,QACE,QAAS,MAOX,QACE,QAAS,UAUX,SACE,QAAS,KAOX,SACE,QAAS"}
|
||||
105
src/res/routes.ts
Normal file
105
src/res/routes.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
export interface VersionRes {
|
||||
version: number
|
||||
}
|
||||
|
||||
export interface TrackRes {
|
||||
title: string,
|
||||
artist: string,
|
||||
album: string,
|
||||
album_artist: string,
|
||||
duration: number,
|
||||
id: number,
|
||||
position: number,
|
||||
album_id: number,
|
||||
track_number: string,
|
||||
can_download: boolean,
|
||||
has_lyrics: boolean
|
||||
}
|
||||
|
||||
export interface StatusRes {
|
||||
status: "stopped" | "playing" | "paused",
|
||||
inc: number,
|
||||
shuffle: boolean,
|
||||
repeat: boolean,
|
||||
playlist: string,
|
||||
playlist_length: number,
|
||||
id: number,
|
||||
title: string,
|
||||
artist: string,
|
||||
album: string,
|
||||
progress: number,
|
||||
auto_stop: boolean,
|
||||
volume: number,
|
||||
position: number,
|
||||
track: TrackRes
|
||||
}
|
||||
|
||||
export function version(host: string) {
|
||||
return fetch(`http://${host}:7815/version?host=${host}`)
|
||||
.then((res) => {
|
||||
if (!res.ok)
|
||||
throw new Error("Could not ping server. Is host correct?")
|
||||
return res.json() as Promise<VersionRes>
|
||||
})
|
||||
}
|
||||
|
||||
export function status(host: string) {
|
||||
return fetch(`http://${host}:7815/status?host=${host}`)
|
||||
.then((res) => {
|
||||
if (!res.ok)
|
||||
throw new Error() // these get handled downstream ;)
|
||||
return res.json() as Promise<StatusRes>
|
||||
})
|
||||
}
|
||||
|
||||
// export function pic(host: string, trackID: number | null, size: "small" | "medium") {
|
||||
// if (trackID === null) {
|
||||
// status(host)
|
||||
// .then((res) => res.id)
|
||||
// .then(id => {
|
||||
// return fetch(`http://localhost:7815/pic?host=${host}&size=${size}&id=${id}`)
|
||||
// .then((res) => {
|
||||
// if (!res.ok)
|
||||
// throw new Error()
|
||||
|
||||
// return res
|
||||
// })
|
||||
// })
|
||||
// } else {
|
||||
// return fetch(`http://localhost:7815/pic?host=${host}&size=${size}&id=${trackID}`)
|
||||
// .then((res) => {
|
||||
// if (!res.ok)
|
||||
// throw new Error()
|
||||
// return res
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
export async function pic(host: string, trackID: number | null, size: "small" | "medium") {
|
||||
if (trackID === null) {
|
||||
const resStatus = await status(host)
|
||||
const id = resStatus.id
|
||||
trackID = id
|
||||
}
|
||||
|
||||
const res = await fetch(`http://${host}:7815/pic?host=${host}&size=${size}&id=${trackID}`)
|
||||
if (!res.ok) throw new Error("Fetch failed")
|
||||
const blob = await res.blob()
|
||||
return blob
|
||||
}
|
||||
|
||||
export function play(host: string) {
|
||||
fetch(`http://${host}:7815/play?host=${host}`)
|
||||
}
|
||||
|
||||
export function pause(host: string) {
|
||||
fetch(`http://${host}:7815/pause?host=${host}`)
|
||||
}
|
||||
|
||||
export function next(host: string) {
|
||||
fetch(`http://${host}:7815/next?host=${host}`)
|
||||
}
|
||||
|
||||
export function back(host: string) {
|
||||
fetch(`http://${host}:7815/back?host=${host}`)
|
||||
}
|
||||
162
src/res/style.css
Normal file
162
src/res/style.css
Normal file
@@ -0,0 +1,162 @@
|
||||
body {
|
||||
font-family: system-ui, sans-serif;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
header {
|
||||
margin: 0 auto;
|
||||
max-width: 80em;
|
||||
box-shadow: 0 0 5px 5px #bbb;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 0 auto;
|
||||
max-width: 80em;
|
||||
padding-bottom: 150px;
|
||||
min-height: 60dvh;
|
||||
max-height: 90dvh;
|
||||
}
|
||||
|
||||
header > p, header > h1, header > sub {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
margin-top: 0px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
div.hr {
|
||||
color: #6100ba;
|
||||
background: #6100ba;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
nav {
|
||||
margin-top: 10px;
|
||||
background: #6100ba;
|
||||
background-image: linear-gradient(to bottom, #6100ba, #3d0076);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
nav > ul {
|
||||
padding-left: 12px;
|
||||
list-style: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav > ul > li > a {
|
||||
color: whitesmoke;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding-left: 10px;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-content: center;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-shadow: 0 0 2px white;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 0 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#details-success {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#details-error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#player {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#player > img {
|
||||
max-width: 512px;
|
||||
max-height: 512px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#player > p {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
#controls {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#controls > input {
|
||||
width: 48px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: #111;
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
header {
|
||||
box-shadow: 0 -5px 5px 5px BLACK;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
|
||||
main {
|
||||
box-shadow: 0 5px 5px 3px black;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body {
|
||||
background: #e4e4e4;
|
||||
}
|
||||
|
||||
header {
|
||||
box-shadow: 0 -5px 5px 5px #bbb;
|
||||
background: white;
|
||||
}
|
||||
|
||||
main {
|
||||
box-shadow: 0 5px 5px 5px #bbb;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
3
src/srv/package.json
Normal file
3
src/srv/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
122
src/srv/proxy.ts
Normal file
122
src/srv/proxy.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/* Proxy to bypass CORS (tauon does not pass these headers) */
|
||||
|
||||
import express from "express"
|
||||
import cors from "cors"
|
||||
import compression from "compression"
|
||||
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(compression())
|
||||
|
||||
app.get("/version", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string") {
|
||||
return res.status(400).send("No host")
|
||||
}
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
fetch(`http://${host}/api1/version`)
|
||||
.then(fetchRes => fetchRes.json())
|
||||
.then(fetchRes => {
|
||||
return res.status(200).send(fetchRes)
|
||||
})
|
||||
.catch((err) => {
|
||||
return res.status(500).send(err)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
app.get("/status", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string") {
|
||||
return res.status(400).send("No host")
|
||||
}
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
fetch(`http://${host}/api1/status`)
|
||||
.then(fetchRes => fetchRes.json())
|
||||
.then(fetchRes => {
|
||||
return res.status(200).send(fetchRes)
|
||||
})
|
||||
.catch((err) => {
|
||||
return res.status(500).send(err)
|
||||
})
|
||||
})
|
||||
|
||||
app.get("/pic", (req, res) => {
|
||||
let host = req.query.host
|
||||
const size = req.query.size
|
||||
const id = req.query.id
|
||||
|
||||
|
||||
if (typeof host !== "string" || !size || !id)
|
||||
return res.status(400).send("Bad parameters")
|
||||
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
|
||||
fetch(`http://${host}/api1/pic/${size}/${id}`)
|
||||
.then(raw => raw.arrayBuffer())
|
||||
.then(arrBuff => Buffer.from(arrBuff))
|
||||
.then(buff => {
|
||||
return res.send(buff)
|
||||
})
|
||||
})
|
||||
|
||||
app.get("/play", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string")
|
||||
return res.status(400).send("Bad host")
|
||||
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
|
||||
fetch(`http://${host}/api1/play`)
|
||||
return res.status(200).end()
|
||||
})
|
||||
|
||||
app.get("/pause", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string")
|
||||
return res.status(400).send("Bad host")
|
||||
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
|
||||
fetch(`http://${host}/api1/pause`)
|
||||
return res.status(200).end()
|
||||
})
|
||||
|
||||
app.get("/next", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string")
|
||||
return res.status(400).send("Bad host")
|
||||
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
|
||||
fetch(`http://${host}/api1/next`)
|
||||
return res.status(200).end()
|
||||
})
|
||||
|
||||
app.get("/back", (req, res) => {
|
||||
let host = req.query.host
|
||||
if (typeof host !== "string")
|
||||
return res.status(400).send("Bad host")
|
||||
|
||||
if (!host.includes(":")) {
|
||||
host = host + ":7814"
|
||||
}
|
||||
|
||||
fetch(`http://${host}/api1/back`)
|
||||
return res.status(200).end()
|
||||
})
|
||||
|
||||
|
||||
app.listen(7815, () => console.log("MuonRC Proxy listening on 7815"))
|
||||
11
src/srv/tsconfig.json
Normal file
11
src/srv/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "nodenext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "nodenext",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"composite": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user