Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ policy live in [Last.fm import matching](docs/architecture/lastfm-import-matchin
- The desktop shell targets macOS arm64, Windows x64/ARM64, and Ubuntu 22.04
amd64/arm64.
- Spotify Premium is required for built-in Spotify playback.
- Spotify restricts third-party access to playlists the current user does not
own; Retune does not request those items.
- Spotify Web API playlist-content access is restricted. Explicit read-only
shadows use separately authorized librespot metadata for saved playlists.
- Audiobook chapters can be synchronized but are not currently playable.

## Domain details
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ log = "0.4"
md-5 = "0.10"
librespot-audio = { version = "0.8", default-features = false }
librespot-core = { version = "0.8", default-features = false, features = ["rustls-tls-native-roots"] }
librespot-metadata = { version = "0.8", default-features = false }
librespot-protocol = { version = "0.8", default-features = false }
protobuf = "3.7"
librespot-playback = { version = "0.8", default-features = false, features = ["rodio-backend", "rustls-tls-native-roots"] }
tauri = { version = "2.11.3", features = [] }
tauri-plugin-dialog = "2"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const APP_COMMANDS: &[&str] = &[
"subscribe_main_events",
"unsubscribe_main_events",
"get_settings",
"open_preferences",
"get_appearance",
"update_settings",
"connection_state",
Expand All @@ -36,6 +37,10 @@ const APP_COMMANDS: &[&str] = &[
"add_spotify_tracks",
"remove_spotify_track",
"playlists_list",
"discover_shadow_playlists",
"shadow_playlist",
"stop_shadowing_playlist",
"refresh_shadow_playlists",
"open_spotify_playlist",
"resolve_spotify_track_destination",
"reorder_playlists",
Expand Down
19 changes: 19 additions & 0 deletions apps/desktop/src-tauri/capabilities/preferences.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "preferences",
"description": "Settings, account setup, and diagnostics for the Preferences window",
"windows": [
"preferences"
],
"platforms": [
"linux",
"macOS",
"windows"
],
"permissions": [
"core:event:allow-listen",
"core:event:allow-unlisten",
"core:window:allow-close",
"preferences-commands"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!

[[permission]]
identifier = "allow-discover-shadow-playlists"
description = "Enables the discover_shadow_playlists command without any pre-configured scope."
commands.allow = ["discover_shadow_playlists"]

[[permission]]
identifier = "deny-discover-shadow-playlists"
description = "Denies the discover_shadow_playlists command without any pre-configured scope."
commands.deny = ["discover_shadow_playlists"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!

[[permission]]
identifier = "allow-open-preferences"
description = "Enables the open_preferences command without any pre-configured scope."
commands.allow = ["open_preferences"]

[[permission]]
identifier = "deny-open-preferences"
description = "Denies the open_preferences command without any pre-configured scope."
commands.deny = ["open_preferences"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!

[[permission]]
identifier = "allow-refresh-shadow-playlists"
description = "Enables the refresh_shadow_playlists command without any pre-configured scope."
commands.allow = ["refresh_shadow_playlists"]

[[permission]]
identifier = "deny-refresh-shadow-playlists"
description = "Denies the refresh_shadow_playlists command without any pre-configured scope."
commands.deny = ["refresh_shadow_playlists"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!

[[permission]]
identifier = "allow-shadow-playlist"
description = "Enables the shadow_playlist command without any pre-configured scope."
commands.allow = ["shadow_playlist"]

[[permission]]
identifier = "deny-shadow-playlist"
description = "Denies the shadow_playlist command without any pre-configured scope."
commands.deny = ["shadow_playlist"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!

[[permission]]
identifier = "allow-stop-shadowing-playlist"
description = "Enables the stop_shadowing_playlist command without any pre-configured scope."
commands.allow = ["stop_shadowing_playlist"]

[[permission]]
identifier = "deny-stop-shadowing-playlist"
description = "Denies the stop_shadowing_playlist command without any pre-configured scope."
commands.deny = ["stop_shadowing_playlist"]
5 changes: 5 additions & 0 deletions apps/desktop/src-tauri/permissions/main.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ permissions = [
"allow-subscribe-main-events",
"allow-unsubscribe-main-events",
"allow-get-settings",
"allow-open-preferences",
"allow-get-appearance",
"allow-update-settings",
"allow-connection-state",
Expand All @@ -39,6 +40,10 @@ permissions = [
"allow-add-spotify-tracks",
"allow-remove-spotify-track",
"allow-playlists-list",
"allow-discover-shadow-playlists",
"allow-shadow-playlist",
"allow-stop-shadowing-playlist",
"allow-refresh-shadow-playlists",
"allow-open-spotify-playlist",
"allow-resolve-spotify-track-destination",
"allow-reorder-playlists",
Expand Down
19 changes: 19 additions & 0 deletions apps/desktop/src-tauri/permissions/preferences.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[[set]]
identifier = "preferences-commands"
description = "Settings, account setup, recovery, and diagnostics in Preferences."
permissions = [
"allow-get-settings",
"allow-update-settings",
"allow-lastfm-state",
"allow-connect-lastfm",
"allow-finish-lastfm",
"allow-disconnect-lastfm",
"allow-lastfm-import-state",
"allow-sync-lastfm-plays",
"allow-open-lastfm-importer",
"allow-removed-retune-tracks",
"allow-restore-retune-track",
"allow-load-diagnostics",
"allow-email-diagnostics",
"allow-open-external-destination",
]
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ mod tests {
owner: None,
track_count: 0,
tracks: Vec::new(),
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: Vec::new(),
}],
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src-tauri/src/lastfm_import/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ fn emit_to_import_windows<T: Clone + Serialize>(
}

fn emit_import_invalidated(app: &tauri::AppHandle) -> Result<(), String> {
app.emit_to("preferences", "lastfm-import-changed", ())
.map_err(|error| error.to_string())?;
emit_to_import_windows(app, "lastfm-import-changed", ())
}

Expand Down
23 changes: 21 additions & 2 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod provider;
mod restore;
mod restore_latch;
mod settings_commands;
mod shadow_playlists;
mod spotify_commands;
mod spotify_membership;
mod spotify_sync_commit;
Expand Down Expand Up @@ -922,7 +923,12 @@ fn install_file_menu(app: &tauri::AppHandle, settings: &Settings) -> tauri::Resu
.show(|_| {});
}
"preferences" => {
let _ = emit_main(app, "open-preferences", ());
let app = app.clone();
tauri::async_runtime::spawn(async move {
if let Err(error) = settings_commands::open_preferences(app.clone()).await {
notify_error(&app, error);
}
});
}
"zoom_in" | "zoom_out" | "actual_size" | "toggle_zebra" | "toggle_browser"
| "theme_system" | "theme_light" | "theme_dark" => {
Expand Down Expand Up @@ -1097,6 +1103,7 @@ fn finish_startup(
),
Arc::new(move |_| {
let _ = emit_main(&lastfm_app, "lastfm-changed", ());
let _ = lastfm_app.emit_to("preferences", "lastfm-changed", ());
}),
);
let restore_mutations = Arc::new(restore_latch::RestoreMutationState::default());
Expand Down Expand Up @@ -1260,6 +1267,7 @@ fn finish_startup(
if import_result.is_ok() {
let _ = profile_app.emit_to("main", "lastfm-import-changed", ());
let _ = profile_app.emit_to("lastfm-importer", "lastfm-import-changed", ());
let _ = profile_app.emit_to("preferences", "lastfm-import-changed", ());
}
if let Err(error) = &lastfm_result {
notify_error(&profile_app, error.clone());
Expand Down Expand Up @@ -1396,7 +1404,7 @@ pub fn run() {
#[cfg(all(desktop, not(test)))]
let builder = builder.plugin(
tauri_plugin_window_state::Builder::default()
.with_denylist(&["lastfm-importer"])
.with_denylist(&["lastfm-importer", "preferences"])
.with_state_flags(
tauri_plugin_window_state::StateFlags::SIZE
| tauri_plugin_window_state::StateFlags::POSITION
Expand Down Expand Up @@ -1426,6 +1434,7 @@ pub fn run() {
main_events::subscribe_main_events,
main_events::unsubscribe_main_events,
settings_commands::get_settings,
settings_commands::open_preferences,
settings_commands::get_appearance,
settings_commands::update_settings,
spotify_commands::connection_state,
Expand All @@ -1445,6 +1454,10 @@ pub fn run() {
spotify_commands::add_spotify_tracks,
spotify_commands::remove_spotify_track,
playlist_commands::playlists_list,
playlist_commands::discover_shadow_playlists,
playlist_commands::shadow_playlist,
playlist_commands::stop_shadowing_playlist,
playlist_commands::refresh_shadow_playlists,
playlist_commands::open_spotify_playlist,
playlist_commands::resolve_spotify_track_destination,
playlist_commands::reorder_playlists,
Expand Down Expand Up @@ -2220,6 +2233,7 @@ mod tests {
owner: None,
track_count: 2,
tracks: vec!["one".into(), "two".into()],
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: vec![],
}],
Expand Down Expand Up @@ -3239,6 +3253,7 @@ mod tests {
owner: None,
track_count: 0,
tracks: vec![],
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: vec![],
})
Expand Down Expand Up @@ -3313,6 +3328,7 @@ mod tests {
)]),
sort_column: Some("plays".into()),
sort_desc: true,
ignore_leading_the: true,
auto_add_spotify_library: false,
auto_connect: false,
spotify_client_id: "exported-machine".into(),
Expand Down Expand Up @@ -3470,6 +3486,7 @@ mod tests {
owner: None,
track_count: 1,
tracks: vec!["spotify:track:restored".into()],
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: vec![],
}],
Expand Down Expand Up @@ -3580,6 +3597,7 @@ mod tests {
owner: None,
track_count: 0,
tracks: vec![],
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: vec![],
}],
Expand Down Expand Up @@ -3681,6 +3699,7 @@ mod tests {
owner: None,
track_count: 0,
tracks: vec![],
shadow: None,
track_metadata_version: playlists::TRACK_METADATA_VERSION,
spotify_tracks: vec![],
}],
Expand Down
10 changes: 10 additions & 0 deletions apps/desktop/src-tauri/src/playback/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ pub(super) struct LocalBackend {
}

impl LocalBackend {
#[cfg(test)]
pub(super) fn interrupt_session_for_test(&mut self) {
let runtime = self.runtime.as_mut().unwrap();
runtime.session.shutdown();
let disconnected = Session::new(runtime.session.config().clone(), None);
disconnected.shutdown();
runtime.player.set_session(disconnected.clone());
runtime.session = disconnected;
}

#[cfg(test)]
pub(super) fn with_snapshot_for_test(snapshot: Snapshot) -> Self {
Self {
Expand Down
Loading
Loading