feat(desktop): wrap the web client in a Tauri app
ci / api / api (push) Successful in 43s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m19s
ci / desktop / rust (desktop proxy) (push) Failing after 3m34s
ci / ts / ts (packages + web) (push) Failing after 2m49s
release / release (версия и заметки) (push) Successful in 5s
ci / db / db (push) Successful in 40s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m12s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m28s
release / android (APK в релиз) (push) Failing after 2m0s
ci / api / api (push) Successful in 43s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m19s
ci / desktop / rust (desktop proxy) (push) Failing after 3m34s
ci / ts / ts (packages + web) (push) Failing after 2m49s
release / release (версия и заметки) (push) Successful in 5s
ci / db / db (push) Successful in 40s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m12s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m28s
release / android (APK в релиз) (push) Failing after 2m0s
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
fa79394869
commit
efe78d7e07
33 files changed
+1056
-20
No files matched your search
@@ -10,6 +10,8 @@ import {
|
||||
type Track,
|
||||
} from '@pipu/core';
|
||||
|
||||
import { desktopHandle } from '../desktop';
|
||||
|
||||
export type { PlayContext, Track };
|
||||
|
||||
export interface WaveInfo {
|
||||
@@ -121,6 +123,7 @@ export class Player {
|
||||
};
|
||||
this.bindAudio();
|
||||
this.bindMediaSession();
|
||||
this.bindDesktopMedia();
|
||||
}
|
||||
|
||||
/** Запуск фоновой отправки событий (парный вызов — dispose). */
|
||||
@@ -137,9 +140,13 @@ export class Player {
|
||||
|
||||
getState = () => this.state;
|
||||
|
||||
private lastDesktop: { id?: string; playing?: boolean } = {};
|
||||
private desktopUnlisten: (() => void) | null = null;
|
||||
|
||||
private update(patch: Partial<PlayerState>) {
|
||||
this.state = { ...this.state, ...patch };
|
||||
for (const fn of this.listeners) fn();
|
||||
this.syncDesktopMedia();
|
||||
}
|
||||
|
||||
private syncQueue() {
|
||||
@@ -678,6 +685,33 @@ export class Player {
|
||||
|
||||
// --- Media Session ---
|
||||
|
||||
private bindDesktopMedia() {
|
||||
void desktopHandle()?.listenMedia((action) => {
|
||||
if (action === 'play') this.play();
|
||||
else if (action === 'pause' || action === 'stop') this.pause();
|
||||
else if (action === 'toggle') this.toggle();
|
||||
else if (action === 'next') this.next();
|
||||
else if (action === 'previous') this.prev();
|
||||
}).then((stop) => {
|
||||
this.desktopUnlisten = stop;
|
||||
});
|
||||
}
|
||||
|
||||
private syncDesktopMedia() {
|
||||
const desktop = desktopHandle();
|
||||
const track = this.state.track;
|
||||
if (!desktop || !track) return;
|
||||
if (this.lastDesktop.id === track.id && this.lastDesktop.playing === this.state.playing) return;
|
||||
this.lastDesktop = { id: track.id, playing: this.state.playing };
|
||||
desktop.setMedia({
|
||||
title: track.title,
|
||||
artist: track.artists.map((a) => a.name).join(', '),
|
||||
album: track.album.title,
|
||||
coverUrl: track.album.cover_url,
|
||||
playing: this.state.playing,
|
||||
});
|
||||
}
|
||||
|
||||
private bindMediaSession() {
|
||||
const ms = typeof navigator !== 'undefined' ? navigator.mediaSession : undefined;
|
||||
if (!ms) return;
|
||||
@@ -855,6 +889,8 @@ export class Player {
|
||||
this.overlap.load();
|
||||
for (const t of this.timers) clearInterval(t);
|
||||
this.timers = [];
|
||||
this.desktopUnlisten?.();
|
||||
this.desktopUnlisten = null;
|
||||
void this.events.flush();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user