mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-10 10:11:46 +00:00
init webnowplaying
This commit is contained in:
@ -172,6 +172,7 @@
|
|||||||
"node-html-parser": "6.1.12",
|
"node-html-parser": "6.1.12",
|
||||||
"node-id3": "0.2.6",
|
"node-id3": "0.2.6",
|
||||||
"peerjs": "1.5.2",
|
"peerjs": "1.5.2",
|
||||||
|
"reconnecting-websocket": "4.4.0",
|
||||||
"semver": "7.6.0",
|
"semver": "7.6.0",
|
||||||
"serve": "14.2.1",
|
"serve": "14.2.1",
|
||||||
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
|
"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",
|
"solid-transition-group": "0.2.3",
|
||||||
"ts-morph": "22.0.0",
|
"ts-morph": "22.0.0",
|
||||||
"vudio": "2.1.1",
|
"vudio": "2.1.1",
|
||||||
|
"ws": "8.16.0",
|
||||||
"x11": "2.3.0",
|
"x11": "2.3.0",
|
||||||
"youtubei.js": "9.1.0"
|
"youtubei.js": "9.1.0"
|
||||||
},
|
},
|
||||||
@ -192,6 +194,7 @@
|
|||||||
"@types/howler": "2.2.11",
|
"@types/howler": "2.2.11",
|
||||||
"@types/html-to-text": "9.0.4",
|
"@types/html-to-text": "9.0.4",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
|
"@types/ws": "8.5.10",
|
||||||
"@typescript-eslint/eslint-plugin": "7.4.0",
|
"@typescript-eslint/eslint-plugin": "7.4.0",
|
||||||
"bufferutil": "4.0.8",
|
"bufferutil": "4.0.8",
|
||||||
"builtin-modules": "3.3.0",
|
"builtin-modules": "3.3.0",
|
||||||
@ -217,8 +220,7 @@
|
|||||||
"vite": "5.2.6",
|
"vite": "5.2.6",
|
||||||
"vite-plugin-inspect": "0.8.3",
|
"vite-plugin-inspect": "0.8.3",
|
||||||
"vite-plugin-resolve": "2.5.1",
|
"vite-plugin-resolve": "2.5.1",
|
||||||
"vite-plugin-solid": "2.10.2",
|
"vite-plugin-solid": "2.10.2"
|
||||||
"ws": "8.16.0"
|
|
||||||
},
|
},
|
||||||
"auto-changelog": {
|
"auto-changelog": {
|
||||||
"hideCredit": true,
|
"hideCredit": true,
|
||||||
|
|||||||
23
pnpm-lock.yaml
generated
23
pnpm-lock.yaml
generated
@ -129,6 +129,9 @@ dependencies:
|
|||||||
peerjs:
|
peerjs:
|
||||||
specifier: 1.5.2
|
specifier: 1.5.2
|
||||||
version: 1.5.2
|
version: 1.5.2
|
||||||
|
reconnecting-websocket:
|
||||||
|
specifier: 4.4.0
|
||||||
|
version: 4.4.0
|
||||||
semver:
|
semver:
|
||||||
specifier: 7.6.0
|
specifier: 7.6.0
|
||||||
version: 7.6.0
|
version: 7.6.0
|
||||||
@ -156,6 +159,9 @@ dependencies:
|
|||||||
vudio:
|
vudio:
|
||||||
specifier: 2.1.1
|
specifier: 2.1.1
|
||||||
version: 2.1.1(patch_hash=7iux5msqpgl3octdmwy4uspwoe)
|
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:
|
x11:
|
||||||
specifier: 2.3.0
|
specifier: 2.3.0
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
@ -185,6 +191,9 @@ devDependencies:
|
|||||||
'@types/semver':
|
'@types/semver':
|
||||||
specifier: 7.5.8
|
specifier: 7.5.8
|
||||||
version: 7.5.8
|
version: 7.5.8
|
||||||
|
'@types/ws':
|
||||||
|
specifier: 8.5.10
|
||||||
|
version: 8.5.10
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: 7.4.0
|
specifier: 7.4.0
|
||||||
version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3)
|
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:
|
vite-plugin-solid:
|
||||||
specifier: 2.10.2
|
specifier: 2.10.2
|
||||||
version: 2.10.2(solid-js@1.8.16)(vite@5.2.6)
|
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:
|
packages:
|
||||||
|
|
||||||
@ -1747,6 +1753,12 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: 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:
|
/@types/yauzl@2.10.3:
|
||||||
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
@ -5711,6 +5723,10 @@ packages:
|
|||||||
util-deprecate: 1.0.2
|
util-deprecate: 1.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/reconnecting-websocket@4.4.0:
|
||||||
|
resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/redent@4.0.0:
|
/redent@4.0.0:
|
||||||
resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==}
|
resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -6851,6 +6867,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bufferutil: 4.0.8
|
bufferutil: 4.0.8
|
||||||
utf-8-validate: 6.0.3
|
utf-8-validate: 6.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/x11@2.3.0:
|
/x11@2.3.0:
|
||||||
resolution: {integrity: sha512-Ep4DbqZkVHvZNVht+vvELcfdpGKnfh2kZuKdXqyZdtJx3UdvgUGrMQ9lwPNV33tDs86MF4YagC6+E2fZXikF6A==}
|
resolution: {integrity: sha512-Ep4DbqZkVHvZNVht+vvELcfdpGKnfh2kZuKdXqyZdtJx3UdvgUGrMQ9lwPNV33tDs86MF4YagC6+E2fZXikF6A==}
|
||||||
|
|||||||
145
src/plugins/webnowplaying/index.ts
Normal file
145
src/plugins/webnowplaying/index.ts
Normal 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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user