init webnowplaying

This commit is contained in:
JellyBrick
2024-03-28 23:05:55 +09:00
parent 9da3ad2fb7
commit 22b74113b6
3 changed files with 169 additions and 5 deletions

View File

@ -172,6 +172,7 @@
"node-html-parser": "6.1.12",
"node-id3": "0.2.6",
"peerjs": "1.5.2",
"reconnecting-websocket": "4.4.0",
"semver": "7.6.0",
"serve": "14.2.1",
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
@ -181,6 +182,7 @@
"solid-transition-group": "0.2.3",
"ts-morph": "22.0.0",
"vudio": "2.1.1",
"ws": "8.16.0",
"x11": "2.3.0",
"youtubei.js": "9.1.0"
},
@ -192,6 +194,7 @@
"@types/howler": "2.2.11",
"@types/html-to-text": "9.0.4",
"@types/semver": "7.5.8",
"@types/ws": "8.5.10",
"@typescript-eslint/eslint-plugin": "7.4.0",
"bufferutil": "4.0.8",
"builtin-modules": "3.3.0",
@ -217,8 +220,7 @@
"vite": "5.2.6",
"vite-plugin-inspect": "0.8.3",
"vite-plugin-resolve": "2.5.1",
"vite-plugin-solid": "2.10.2",
"ws": "8.16.0"
"vite-plugin-solid": "2.10.2"
},
"auto-changelog": {
"hideCredit": true,

23
pnpm-lock.yaml generated
View File

@ -129,6 +129,9 @@ dependencies:
peerjs:
specifier: 1.5.2
version: 1.5.2
reconnecting-websocket:
specifier: 4.4.0
version: 4.4.0
semver:
specifier: 7.6.0
version: 7.6.0
@ -156,6 +159,9 @@ dependencies:
vudio:
specifier: 2.1.1
version: 2.1.1(patch_hash=7iux5msqpgl3octdmwy4uspwoe)
ws:
specifier: 8.16.0
version: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
x11:
specifier: 2.3.0
version: 2.3.0
@ -185,6 +191,9 @@ devDependencies:
'@types/semver':
specifier: 7.5.8
version: 7.5.8
'@types/ws':
specifier: 8.5.10
version: 8.5.10
'@typescript-eslint/eslint-plugin':
specifier: 7.4.0
version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3)
@ -263,9 +272,6 @@ devDependencies:
vite-plugin-solid:
specifier: 2.10.2
version: 2.10.2(solid-js@1.8.16)(vite@5.2.6)
ws:
specifier: 8.16.0
version: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
packages:
@ -1747,6 +1753,12 @@ packages:
dev: true
optional: true
/@types/ws@8.5.10:
resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
dependencies:
'@types/node': 20.11.30
dev: true
/@types/yauzl@2.10.3:
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
requiresBuild: true
@ -5711,6 +5723,10 @@ packages:
util-deprecate: 1.0.2
dev: true
/reconnecting-websocket@4.4.0:
resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==}
dev: false
/redent@4.0.0:
resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==}
engines: {node: '>=12'}
@ -6851,6 +6867,7 @@ packages:
dependencies:
bufferutil: 4.0.8
utf-8-validate: 6.0.3
dev: false
/x11@2.3.0:
resolution: {integrity: sha512-Ep4DbqZkVHvZNVht+vvELcfdpGKnfh2kZuKdXqyZdtJx3UdvgUGrMQ9lwPNV33tDs86MF4YagC6+E2fZXikF6A==}

View File

@ -0,0 +1,145 @@
import { net } from 'electron';
import is from 'electron-is';
import { createPlugin } from '@/utils';
import registerCallback from '@/providers/song-info';
import { t } from '@/i18n';
import { WebSocket } from 'ws';
import ReconnectingWebSocket from 'reconnecting-websocket';
import type { RepeatMode } from '@/types/datahost-get-state';
interface Data {
player: string;
state: 'PLAYING' | 'PAUSED' | 'STOPPED';
title: string;
artist: string;
album: string;
cover: string;
duration: string;
position: string;
volume: number;
rating: number;
repeat: 'ALL' | 'ONE' | 'NONE';
shuffle: boolean;
}
export default createPlugin({
name: () => t('plugins.webnowplaying.name'),
description: () => t('plugins.webnowplaying.description'),
restartNeeded: true,
config: {
enabled: false,
},
backend: {
liteMode: false,
data: {
player: 'YouTube Music',
state: 'STOPPED',
title: '',
artist: '',
album: '',
cover: '',
duration: '0:00',
// position and volume are fetched in sendUpdate()
position: '0:00',
volume: 100,
rating: 0,
repeat: 'NONE',
shuffle: false
} as Data,
start({ ipc }) {
const timeInSecondsToString = (timeInSeconds: number) => {
const timeInMinutes = Math.floor(timeInSeconds / 60);
if (timeInMinutes < 60) return `${timeInMinutes}:${Math.floor(timeInSeconds % 60).toString().padStart(2, '0')}`;
return `${Math.floor(timeInMinutes / 60)}:${Math.floor(timeInMinutes % 60).toString().padStart(2, '0')}:${Math.floor(timeInSeconds % 60).toString().padStart(2, '0')}`;
};
const ws = new ReconnectingWebSocket('ws://localhost:8974', undefined, {
WebSocket: WebSocket,
maxEnqueuedMessages: 0,
});
ws.onmessage = () => {
};
const post = (data: Data) => {
const port = 1608;
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
};
const url = `http://127.0.0.1:${port}/`;
net
.fetch(url, {
method: this.liteMode ? 'OPTIONS' : 'POST',
headers,
keepalive: true,
body: this.liteMode ? undefined : JSON.stringify({ data }),
})
.then(() => {
if (this.liteMode) {
this.liteMode = false;
console.debug(
`obs-tuna webserver at port ${port} is now accessible. disable lite mode`,
);
post(data);
}
})
.catch((error: { code: number; errno: number }) => {
if (!this.liteMode && is.dev()) {
console.debug(
`Error: '${
error.code || error.errno
}' - when trying to access obs-tuna webserver at port ${port}. enable lite mode`,
);
this.liteMode = true;
}
});
};
ipc.on('ytmd:player-api-loaded', () => {
ipc.send('ytmd:setup-time-changed-listener');
ipc.send('ytmd:setup-repeat-changed-listener');
ipc.send('ytmd:setup-volume-changed-listener');
});
ipc.on('ytmd:time-changed', (t: number) => {
if (!this.data.title) {
return;
}
this.data.position = timeInSecondsToString(t);
post(this.data);
});
ipc.on('ytmd:repeat-changed', (mode: RepeatMode) => {
this.data.repeat = mode;
post(this.data);
});
ipc.on('ytmd:volume-changed', (newVolume: number) => {
this.data.volume = newVolume;
post(this.data);
});
registerCallback((songInfo) => {
if (!songInfo.title && !songInfo.artist) {
return;
}
this.data.duration = timeInSecondsToString(songInfo.songDuration);
this.data.position = timeInSecondsToString(songInfo.elapsedSeconds ?? 0);
this.data.cover = songInfo.imageSrc ?? '';
this.data.title = songInfo.title;
this.data.artist = songInfo.artist;
this.data.state = songInfo.isPaused ? 'PAUSED' : 'PLAYING';
this.data.album = songInfo.album ?? '';
post(this.data);
});
},
},
});