mirror of
https://github.com/pisto/oggify
synced 2024-11-21 21:37:30 +00:00
WIP
This commit is contained in:
commit
c7f7adecec
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
85
src/main.rs
Normal file
85
src/main.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
extern crate tokio_core;
|
||||||
|
extern crate regex;
|
||||||
|
extern crate librespot_core;
|
||||||
|
extern crate librespot_metadata;
|
||||||
|
extern crate librespot_audio;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
extern crate env_logger;
|
||||||
|
extern crate scoped_threadpool;
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::env;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::io::{self, Read, BufRead, Result};
|
||||||
|
use tokio_core::reactor::Core;
|
||||||
|
use regex::Regex;
|
||||||
|
use env_logger::{Builder, Env};
|
||||||
|
use scoped_threadpool::Pool;
|
||||||
|
|
||||||
|
use librespot_core::authentication::Credentials;
|
||||||
|
use librespot_core::config::SessionConfig;
|
||||||
|
use librespot_core::session::Session;
|
||||||
|
use librespot_core::spotify_id::SpotifyId;
|
||||||
|
use librespot_metadata::{Metadata, FileFormat, Track, Artist};
|
||||||
|
use librespot_audio::{AudioDecrypt, AudioFile};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||||
|
|
||||||
|
let args: Vec<_> = env::args().collect();
|
||||||
|
assert!(args.len() == 3, "Usage: {} USERNAME PASSWORD < tracks_file", args[0]);
|
||||||
|
|
||||||
|
let mut core = Core::new().unwrap();
|
||||||
|
let handle = core.handle();
|
||||||
|
let session_config = SessionConfig::default();
|
||||||
|
let credentials = Credentials::with_password(args[1].to_owned(), args[2].to_owned());
|
||||||
|
info!("Connecting ...");
|
||||||
|
let session = core
|
||||||
|
.run(Session::connect(session_config, credentials, None, handle))
|
||||||
|
.unwrap();
|
||||||
|
info!("Connected!");
|
||||||
|
|
||||||
|
let mut threadpool = Pool::new(1);
|
||||||
|
|
||||||
|
let spotify_uri = Regex::new(r"spotify:track:([[:alnum:]]+)").unwrap();
|
||||||
|
let spotify_url = Regex::new(r"open\.spotify\.com/track/([[:alnum:]]+)").unwrap();
|
||||||
|
|
||||||
|
io::stdin().lock().lines()
|
||||||
|
.filter_map(|line|
|
||||||
|
line.ok().and_then(|str|
|
||||||
|
spotify_uri.captures(&str).or(spotify_url.captures(&str))
|
||||||
|
.or_else(|| { warn!("Cannot parse track from string {}", str); None })
|
||||||
|
.and_then(|capture|SpotifyId::from_base62(&capture[1]).ok())))
|
||||||
|
.for_each(|id|{
|
||||||
|
info!("Getting track {}...", id.to_base62());
|
||||||
|
let track = core.run(Track::get(&session, id)).expect("Cannot get track metadata");
|
||||||
|
let artists_strs: Vec<_> = track.artists.iter().map(|id|core.run(Artist::get(&session, *id)).expect("Cannot get artist metadata").name).collect();
|
||||||
|
let artists_display = artists_strs.join(", ");
|
||||||
|
let fname = format!("{} - {}.ogg", artists_display, track.name);
|
||||||
|
debug!("File formats: {}", track.files.keys().map(|filetype|format!("{:?}", filetype)).collect::<Vec<_>>().join(" "));
|
||||||
|
let file_id = track.files.get(&FileFormat::OGG_VORBIS_320)
|
||||||
|
.or(track.files.get(&FileFormat::OGG_VORBIS_160))
|
||||||
|
.or(track.files.get(&FileFormat::OGG_VORBIS_320))
|
||||||
|
.expect("Could not find a OGG_VORBIS format for the track.");
|
||||||
|
let key = core.run(session.audio_key().request(track.id, *file_id)).expect("Cannot get audio key");
|
||||||
|
let mut encrypted_file = core.run(AudioFile::open(&session, *file_id)).unwrap();
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut read_all: Result<usize> = Ok(0);
|
||||||
|
let fetched = AtomicBool::new(false);
|
||||||
|
threadpool.scoped(|scope|{
|
||||||
|
scope.execute(||{
|
||||||
|
read_all = encrypted_file.read_to_end(&mut buffer);
|
||||||
|
fetched.store(true, Ordering::Release);
|
||||||
|
});
|
||||||
|
while !fetched.load(Ordering::Acquire) {
|
||||||
|
core.turn(Some(Duration::from_millis(100)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
read_all.expect("Cannot read file stream");
|
||||||
|
let mut decrypted_buffer = Vec::new();
|
||||||
|
AudioDecrypt::new(key, &buffer[..]).read_to_end(&mut decrypted_buffer).expect("Cannot decrypt stream");
|
||||||
|
std::fs::write(&fname, &decrypted_buffer[0xa7..]).expect("Cannot write decrypted track");
|
||||||
|
info!("Filename: {}", fname);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user