mirror of
https://github.com/Felitendo/spotifast.git
synced 2026-11-01 09:23:26 +01:00
The log file, stderr and the panic log are set up by fastframe-log with Spotifast's own default filters and paths, replacing the env_logger set-up, its tee to the log file, and the panic hook. Behaviour changes: - A panic's line in panic.log now keeps its message with any link removed, on the same line as the location (`... on thread "main", panic at src/x.rs:1:2: message`), where it used to write the raw message, which could quote a URL with a token. The default hook is no longer chained, so the raw message and the backtrace hint are not printed to stderr either; the same redacted line is. - Log lines read `[time LEVEL target] message`, with the level no longer padded or coloured on a terminal. - The start line says `Starting spotifast <version> on <os> (<arch>)`, lowercase, and a log file that cannot be created is reported through the log (on stderr) instead of a bare message.
71 lines
2.8 KiB
Rust
71 lines
2.8 KiB
Rust
//! Diagnostic: what Spotify's own permission service says about each
|
|
//! playlist in the account's rootlist, run with the stored playback
|
|
//! credential. The Web API's `collaborative` flag misses playlists shared by
|
|
//! invitation; the rootlist's decorated `capabilities` do not.
|
|
//!
|
|
//! cargo run --example rootlist_probe
|
|
|
|
use librespot_core::{Session, SessionConfig, cache::Cache};
|
|
use librespot_protocol::playlist4_external::SelectedListContent;
|
|
use protobuf::Message as _;
|
|
|
|
fn main() -> anyhow::Result<()> {
|
|
fastframe_log::Logging::new("spotifast", env!("CARGO_PKG_VERSION"))
|
|
.filter("warn")
|
|
.init()?;
|
|
|
|
let dirs = spotifast::paths::AppDirs::discover();
|
|
let cache = Cache::new::<&std::path::Path>(None, None, None, None)?.with_memory_credentials();
|
|
|
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()?;
|
|
runtime.block_on(async move {
|
|
let store = spotifast::credentials::Store::new(dirs);
|
|
let loaded = store.lease(spotifast::credentials::Slot::Playback).load().await?;
|
|
if let Some(warning) = loaded.warning {
|
|
eprintln!("{warning}");
|
|
}
|
|
let Some(spotifast::credentials::Grant::Playback(credentials)) = loaded.grant else {
|
|
anyhow::bail!("Enable playback in Spotifast first");
|
|
};
|
|
let session = Session::new(SessionConfig::default(), Some(cache));
|
|
session.connect(credentials, false).await?;
|
|
println!("connected as {}", session.username());
|
|
|
|
let mut from = 0usize;
|
|
loop {
|
|
let bytes = session.spclient().get_rootlist(from, Some(500)).await?;
|
|
let content = SelectedListContent::parse_from_bytes(&bytes)?;
|
|
let Some(contents) = content.contents.into_option() else {
|
|
break;
|
|
};
|
|
let count = contents.items.len();
|
|
let truncated = contents.truncated();
|
|
println!(
|
|
"page from={from}: {count} items, {} meta items",
|
|
contents.meta_items.len()
|
|
);
|
|
for (item, meta) in contents.items.iter().zip(contents.meta_items.iter()) {
|
|
let caps = meta.capabilities.as_ref();
|
|
println!(
|
|
"{:<40} owner={:<24} collaborative={:<5} can_view={:?} can_edit_items={:?} can_edit_metadata={:?} name={:?}",
|
|
item.uri(),
|
|
meta.owner_username(),
|
|
meta.attributes.collaborative(),
|
|
caps.map(|c| c.can_view()),
|
|
caps.map(|c| c.can_edit_items()),
|
|
caps.map(|c| c.can_edit_metadata()),
|
|
meta.attributes.name(),
|
|
);
|
|
}
|
|
if !truncated || count == 0 {
|
|
break;
|
|
}
|
|
from += count;
|
|
}
|
|
anyhow::Ok(())
|
|
})?;
|
|
Ok(())
|
|
}
|