mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
7921f23927
- Switch from `lewton` to `Symphonia`. This is a pure Rust demuxer and decoder in active development that supports a wide range of formats, including Ogg Vorbis, MP3, AAC and FLAC for future HiFi support. At the moment only Ogg Vorbis and MP3 are enabled; all AAC files are DRM-protected. - Bump MSRV to 1.51, required for `Symphonia`. - Filter out all files whose format is not specified. - Not all episodes seem to be encrypted. If we can't get an audio key, try and see if we can play the file without decryption. - After seeking, report the actual position instead of the target. - Remove the 0xa7 bytes offset from `Subfile`, `Symphonia` does not balk at Spotify's custom Ogg packet before it. This also simplifies handling of formats other than Ogg Vorbis. - When there is no next track to load, signal the UI that the player has stopped. Before, the player would get stuck in an infinite reloading loop when there was only one track in the queue and that track could not be loaded.
57 lines
1.4 KiB
Rust
57 lines
1.4 KiB
Rust
use std::io;
|
|
|
|
use aes_ctr::{
|
|
cipher::{
|
|
generic_array::GenericArray, NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek,
|
|
},
|
|
Aes128Ctr,
|
|
};
|
|
|
|
use librespot_core::audio_key::AudioKey;
|
|
|
|
const AUDIO_AESIV: [u8; 16] = [
|
|
0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb, 0xcf, 0x77, 0xeb, 0xe8, 0xbc, 0x64, 0x3f, 0x63, 0x0d, 0x93,
|
|
];
|
|
|
|
pub struct AudioDecrypt<T: io::Read> {
|
|
// a `None` cipher is a convenience to make `AudioDecrypt` pass files unaltered
|
|
cipher: Option<Aes128Ctr>,
|
|
reader: T,
|
|
}
|
|
|
|
impl<T: io::Read> AudioDecrypt<T> {
|
|
pub fn new(key: Option<AudioKey>, reader: T) -> AudioDecrypt<T> {
|
|
let cipher = key.map(|key| {
|
|
Aes128Ctr::new(
|
|
GenericArray::from_slice(&key.0),
|
|
GenericArray::from_slice(&AUDIO_AESIV),
|
|
)
|
|
});
|
|
|
|
AudioDecrypt { cipher, reader }
|
|
}
|
|
}
|
|
|
|
impl<T: io::Read> io::Read for AudioDecrypt<T> {
|
|
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
|
let len = self.reader.read(output)?;
|
|
|
|
if let Some(ref mut cipher) = self.cipher {
|
|
cipher.apply_keystream(&mut output[..len]);
|
|
}
|
|
|
|
Ok(len)
|
|
}
|
|
}
|
|
|
|
impl<T: io::Read + io::Seek> io::Seek for AudioDecrypt<T> {
|
|
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
|
let newpos = self.reader.seek(pos)?;
|
|
|
|
if let Some(ref mut cipher) = self.cipher {
|
|
cipher.seek(newpos);
|
|
}
|
|
|
|
Ok(newpos)
|
|
}
|
|
}
|