Big Debug of PMOQobuz step 3
This commit is contained in:
@@ -45,6 +45,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("💾 Initializing caches...");
|
||||
let cover_cache = Arc::new(CoverCache::new("./cache/qobuz-covers", 500)?);
|
||||
let audio_cache = Arc::new(AudioCache::new("./cache/qobuz-audio", 100)?);
|
||||
|
||||
// IMPORTANT: Register audio cache globally so PlaylistManager can access it
|
||||
pmoplaylist::register_audio_cache(audio_cache.clone());
|
||||
|
||||
println!("✅ Caches initialized\n");
|
||||
|
||||
// Step 3: Create QobuzSource with caches
|
||||
|
||||
47
pmoqobuz/examples/show_secrets.rs
Normal file
47
pmoqobuz/examples/show_secrets.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! Affiche tous les secrets du Spoofer Rust
|
||||
|
||||
use anyhow::Result;
|
||||
use pmoqobuz::api::Spoofer;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
println!("=== Rust Spoofer Secrets ===\n");
|
||||
|
||||
let spoofer = Spoofer::new().await?;
|
||||
|
||||
// App ID
|
||||
let app_id = spoofer.get_app_id()?;
|
||||
println!("App ID: {}\n", app_id);
|
||||
|
||||
// App Secret (MD5 hash from bundle)
|
||||
match spoofer.get_app_secret() {
|
||||
Ok(app_secret) => {
|
||||
println!("App Secret (from bundle.js):");
|
||||
println!(" Full value: {}", app_secret);
|
||||
println!(" Length: {}\n", app_secret.len());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("App Secret: Error - {}\n", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Timezone secrets
|
||||
match spoofer.get_secrets() {
|
||||
Ok(secrets) => {
|
||||
println!("Timezone Secrets:");
|
||||
println!(" Number of secrets: {}\n", secrets.len());
|
||||
|
||||
for (i, (tz, secret)) in secrets.iter().enumerate() {
|
||||
println!("Secret {} (timezone: {}):", i + 1, tz);
|
||||
println!(" Full value: {}", secret);
|
||||
println!(" Length: {}", secret.len());
|
||||
println!();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Timezone Secrets: Error - {}\n", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -92,6 +92,20 @@ impl Spoofer {
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Extrait l'appSecret depuis le bundle (secret à 32 caractères)
|
||||
fn get_app_secret(&self) -> Result<String> {
|
||||
let captures = self
|
||||
.app_id_regex
|
||||
.captures(&self.bundle)
|
||||
.ok_or_else(|| anyhow::anyhow!("AppSecret non trouvé dans le bundle"))?;
|
||||
|
||||
Ok(captures
|
||||
.name("secret")
|
||||
.ok_or_else(|| anyhow::anyhow!("Groupe secret non trouvé"))?
|
||||
.as_str()
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Extrait les secrets depuis le bundle
|
||||
fn get_secrets(&self) -> Result<IndexMap<String, String>> {
|
||||
// Étape 1: Extraire tous les seed/timezone pairs
|
||||
@@ -222,8 +236,15 @@ async fn main() -> Result<()> {
|
||||
Err(e) => eprintln!("Erreur lors de l'extraction de l'App ID: {}", e),
|
||||
}
|
||||
|
||||
// Extraire les secrets
|
||||
println!("\n--- Secrets ---");
|
||||
// Extraire l'appSecret (32 caractères)
|
||||
println!("\n--- AppSecret (32 chars) ---");
|
||||
match spoofer.get_app_secret() {
|
||||
Ok(secret) => println!("AppSecret: {}", secret),
|
||||
Err(e) => eprintln!("Erreur lors de l'extraction de l'AppSecret: {}", e),
|
||||
}
|
||||
|
||||
// Extraire les secrets timezone
|
||||
println!("\n--- Secrets timezone (décodés base64) ---");
|
||||
match spoofer.get_secrets() {
|
||||
Ok(secrets) => {
|
||||
for (timezone, secret) in secrets {
|
||||
|
||||
64
pmoqobuz/examples/test_getfileurl.rs
Normal file
64
pmoqobuz/examples/test_getfileurl.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
//! Test simplifié - va directement à get_file_url
|
||||
//! Pour comparaison avec Python via fake server
|
||||
//!
|
||||
//! Ce test est conçu pour être utilisé avec le fake_qobuz_server.py
|
||||
//! Les credentials sont hardcodés car le fake server les accepte tous
|
||||
|
||||
use anyhow::Result;
|
||||
use pmoqobuz::api::{QobuzApi, Spoofer};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Initialiser le logging
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
println!("=== Test get_file_url (Rust) ===\n");
|
||||
|
||||
// Track ID connu (récupéré du test Python)
|
||||
let track_id = "19557883";
|
||||
let format_id = 27;
|
||||
|
||||
println!("1. Creating QobuzApi (auto-initializes Spoofer)...");
|
||||
let spoofer = Spoofer::new().await?;
|
||||
let app_id = spoofer.get_app_id()?;
|
||||
let app_secret = spoofer.get_app_secret()?;
|
||||
|
||||
let mut api = QobuzApi::with_raw_secret(&app_id, &app_secret)?;
|
||||
|
||||
// Configurer format_id = 27 (comme Python)
|
||||
use pmoqobuz::AudioFormat;
|
||||
api.set_format(AudioFormat::Flac_HiRes_192);
|
||||
|
||||
println!(" ✓ API created");
|
||||
println!(" App ID: {}", app_id);
|
||||
println!(" Format: 27 (Flac_HiRes_192) - same as Python");
|
||||
|
||||
println!("\n2. Logging in...");
|
||||
println!(" Using fake credentials (fake server accepts all)");
|
||||
let username = "eric@coissac.eu";
|
||||
let password = "fake_password";
|
||||
|
||||
let user = api.login(username, password).await?;
|
||||
println!(" ✓ Login successful - User ID: {}", user.user_id);
|
||||
println!(" Token: {}...", &user.token[..20.min(user.token.len())]);
|
||||
|
||||
println!("\n3. Calling track/getFileUrl...");
|
||||
println!(" Track ID: {}", track_id);
|
||||
println!(" Format ID: {} (default)", format_id);
|
||||
println!(" ⚠️ THIS CALL IS SIGNED - Watch fake server logs!\n");
|
||||
|
||||
match api.get_file_url(track_id).await {
|
||||
Ok(stream_info) => {
|
||||
println!(" ✓ Success!");
|
||||
println!(" URL: {}...", &stream_info.url[..80.min(stream_info.url.len())]);
|
||||
println!(" MIME type: {}", stream_info.mime_type);
|
||||
}
|
||||
Err(e) => {
|
||||
println!(" ✗ Failed: {}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n=== Test completed successfully! ===");
|
||||
Ok(())
|
||||
}
|
||||
57
pmoqobuz/examples/test_signature.rs
Normal file
57
pmoqobuz/examples/test_signature.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
//! Test de signature MD5 avec timestamp fixe
|
||||
//! Compare la signature générée par Rust avec celle de Python
|
||||
|
||||
use anyhow::Result;
|
||||
use pmoqobuz::api::{signing, Spoofer};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
println!("=== Test de signature MD5 ===\n");
|
||||
|
||||
// Récupérer le secret depuis Spoofer (timezone secrets, comme Python)
|
||||
println!("1. Getting secret from Spoofer...");
|
||||
let spoofer = Spoofer::new().await?;
|
||||
let timezone_secrets = spoofer.get_secrets()?;
|
||||
let app_secret = timezone_secrets.values().next().unwrap(); // Premier secret (comme Python)
|
||||
println!(" ✓ Secret retrieved (length: {} bytes)", app_secret.len());
|
||||
println!(" Using timezone secret (like Python), not App Secret");
|
||||
|
||||
// Paramètres du test
|
||||
let track_id = "19557883";
|
||||
let format_id = "27";
|
||||
let intent = "stream";
|
||||
|
||||
// TIMESTAMP FIXE pour comparaison
|
||||
let timestamp = "1234567890.123456";
|
||||
|
||||
println!("\n2. Computing signature with FIXED timestamp:");
|
||||
println!(" track_id: {}", track_id);
|
||||
println!(" format_id: {}", format_id);
|
||||
println!(" intent: {}", intent);
|
||||
println!(" timestamp: {}", timestamp);
|
||||
println!(" secret: {}... (first 10 chars)", &app_secret[..10.min(app_secret.len())]);
|
||||
|
||||
// Calculer la signature
|
||||
let signature = signing::sign_track_get_file_url(
|
||||
format_id,
|
||||
intent,
|
||||
track_id,
|
||||
timestamp,
|
||||
app_secret.as_bytes(),
|
||||
);
|
||||
|
||||
println!("\n3. Result:");
|
||||
println!(" Signature: {}", signature);
|
||||
println!("\n✓ You can now compare this signature with Python using the same timestamp.");
|
||||
println!("\nPython test command:");
|
||||
println!(" python3 -c \"");
|
||||
println!("import hashlib");
|
||||
println!("secret = '{}'", app_secret);
|
||||
println!("ts = '{}'", timestamp);
|
||||
println!("s = 'trackgetFileUrlformat_id27intentstreamtrack_id19557883' + ts");
|
||||
println!("s = s.encode('ASCII') + secret.encode('utf-8')");
|
||||
println!("print('Signature:', hashlib.md5(s).hexdigest())");
|
||||
println!(" \"");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user