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

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mrleo1nidandCursor committed 2026-10-21 23:45:03 +03:00
1 parent fa79394869
commit efe78d7e07
33 files changed
+1056 -20

No files matched your search

+36
View File
@@ -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();
}
}