mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 12:57:01 +02:00
Three outside sources can now be played through the game's own music
player. Each has its own row in the music screen, shown only when it is
set up, with tiles that behave like the game's playlists: track name,
cover, pause, next, and pressing a row to start that track.
How the sound gets in
- The game's song decoder is hooked. While one of these tiles is on, the
audio of the game song behind it (its "carrier") is replaced, block by
block, with the outside source's audio. The game's volume, fades and
pausing still apply.
- Rows are songs of our own registered with the game's music registry
(copies of a real song's asset with their own artist and title), so no
game song is borrowed or renamed to list a track.
Spotify
- The game is a Spotify Connect device ("ReSkate"), built on librespot
and linked into ReSkate.dll (SpotifyHelper/, Rust). Audio, track info
and controls come straight from Spotify. Needs Premium.
- Optional sign-in through the Web API lists the player's playlists and
Liked Songs as tiles with their tracks.
- librespot can no longer end the process (it does so on a free account
and on playback errors); only its thread is stopped.
YouTube Music
- Videos and playlists added by link. yt-dlp is fetched on request into
<Local AppData>\ReSkate\bin and checked against its published sums;
decoding is done in the DLL, so no ffmpeg.
- Private and age-restricted songs: cookies.txt or a browser's sign-in,
with QuickJS fetched as the JavaScript runtime yt-dlp then needs
(Node.js is used instead when installed).
External Audio
- Any app's sound, captured per process from Windows, with the app's own
output turned down while it plays through the game.
Setup page
- "spotify setup" opens http://127.0.0.1:8421/: device status, sign-ins,
YouTube links and tools, the external app, loudness. Loopback only;
changes are accepted from its own page only.
Also
- Speakers in the world play the tile's audio; grabbing one keeps the
player on their tile.
- Playlists added while the game runs are sent to the music screen live.
- MUSIC-SETUP.md: setup guide for players.
Building the Spotify device and the YouTube decoder needs cargo; without
it ReSkate.dll builds without them.
38 lines
1.8 KiB
C++
38 lines
1.8 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// What a music player outside the game is playing, and its transport buttons: Spotify's
|
|
// desktop app first, else whichever player Windows counts as the current one. This goes through
|
|
// Windows' own media session interface (the one the volume flyout and media keys use), so it
|
|
// needs no login and no account with anyone; the sound stays that player's own.
|
|
namespace dingosdk::external_player {
|
|
struct Track {
|
|
bool available{}; // a player with a session is running
|
|
bool spotify{}; // that player is Spotify
|
|
bool playing{};
|
|
bool can_next{}, can_previous{}, can_pause{}, can_play{};
|
|
std::string app; // the player's application id, as Windows names it
|
|
std::string title, artist, album; // UTF-8
|
|
std::vector<std::uint8_t> artwork; // the cover as the player gives it (PNG or JPEG bytes), or empty
|
|
std::uint64_t revision{}; // changes whenever anything above does
|
|
std::uint64_t artwork_revision{}; // changes whenever the cover does
|
|
};
|
|
enum class Command { play, pause, toggle, next, previous };
|
|
|
|
// Starts the watcher (a thread of its own); once. Nothing is read before this.
|
|
void start() noexcept;
|
|
// Stops it and waits for its thread. Safe when it was never started.
|
|
void stop() noexcept;
|
|
// The last track seen. Any thread; a copy.
|
|
Track now();
|
|
// Only what changes often, without copying the cover. Any thread.
|
|
std::uint64_t revision() noexcept;
|
|
// Asks the player to do it. Any thread; done by the watcher, a moment later.
|
|
void send(Command command) noexcept;
|
|
// Whose session it is: Spotify's (empty, as it begins), or that of the application of this
|
|
// name ("chrome.exe"), for which Windows' current one is taken when it has none of its own.
|
|
void use_app(const std::string& executable);
|
|
}
|