140 lines
4.6 KiB
Rust
140 lines
4.6 KiB
Rust
//! Additional utilities for interacting with Spotify
|
|
|
|
use crate::pb::AudioFileFormat;
|
|
|
|
pub type SocketAddress = (String, u16);
|
|
|
|
/// User agent for HTTP requests
|
|
pub const USER_AGENT: &str = "Spotify/124500454 Linux/0 (PC desktop)";
|
|
|
|
/// Spotify app version
|
|
pub const SPOTIFY_VERSION: &str = "1.2.31.1205.g4d59ad7c";
|
|
|
|
/// Spotify app version number
|
|
pub const SPOTIFY_VERSION_NUMBER: u64 = 117300517;
|
|
|
|
/// Spotify OAuth client ID
|
|
pub const SPOTIFY_CLIENT_ID: &str = "65b708073fc0480ea92a077233ca87bd";
|
|
|
|
/// AES128 initialization vector for audio decryption
|
|
pub const AUDIO_AESIV: [u8; 16] = [
|
|
0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb, 0xcf, 0x77, 0xeb, 0xe8, 0xbc, 0x64, 0x3f, 0x63, 0x0d, 0x93,
|
|
];
|
|
|
|
pub(crate) trait Seq {
|
|
fn next(&self) -> Self;
|
|
}
|
|
|
|
macro_rules! impl_seq {
|
|
($($ty:ty)*) => { $(
|
|
impl Seq for $ty {
|
|
fn next(&self) -> Self { (*self).wrapping_add(1) }
|
|
}
|
|
)* }
|
|
}
|
|
|
|
impl_seq!(u8 u16 u32 u64 usize);
|
|
|
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
|
pub(crate) struct SeqGenerator<T: Seq>(T);
|
|
|
|
impl<T: Seq> SeqGenerator<T> {
|
|
pub fn new(value: T) -> Self {
|
|
SeqGenerator(value)
|
|
}
|
|
|
|
pub fn get(&mut self) -> T {
|
|
let value = self.0.next();
|
|
std::mem::replace(&mut self.0, value)
|
|
}
|
|
}
|
|
|
|
pub fn audio_format_extension(format: AudioFileFormat) -> Option<&'static str> {
|
|
match format {
|
|
AudioFileFormat::OGG_VORBIS_96
|
|
| AudioFileFormat::OGG_VORBIS_160
|
|
| AudioFileFormat::OGG_VORBIS_320 => Some(".ogg"),
|
|
AudioFileFormat::MP3_96
|
|
| AudioFileFormat::MP3_160
|
|
| AudioFileFormat::MP3_160_ENC
|
|
| AudioFileFormat::MP3_256
|
|
| AudioFileFormat::MP3_320 => Some(".mp3"),
|
|
AudioFileFormat::AAC_24 | AudioFileFormat::AAC_48 => Some(".aac"),
|
|
AudioFileFormat::MP4_128
|
|
| AudioFileFormat::MP4_128_DUAL
|
|
| AudioFileFormat::MP4_256
|
|
| AudioFileFormat::MP4_256_DUAL => Some(".m4a"),
|
|
AudioFileFormat::FLAC_FLAC => Some(".flac"),
|
|
AudioFileFormat::UNKNOWN_FORMAT => None,
|
|
}
|
|
}
|
|
|
|
pub fn audio_format_mime(format: AudioFileFormat) -> Option<&'static str> {
|
|
match format {
|
|
AudioFileFormat::OGG_VORBIS_96
|
|
| AudioFileFormat::OGG_VORBIS_160
|
|
| AudioFileFormat::OGG_VORBIS_320 => Some("audio/ogg"),
|
|
AudioFileFormat::MP3_96
|
|
| AudioFileFormat::MP3_160
|
|
| AudioFileFormat::MP3_160_ENC
|
|
| AudioFileFormat::MP3_256
|
|
| AudioFileFormat::MP3_320 => Some("audio/mp3"),
|
|
AudioFileFormat::AAC_24 | AudioFileFormat::AAC_48 => Some("audio/aac"),
|
|
AudioFileFormat::MP4_128
|
|
| AudioFileFormat::MP4_128_DUAL
|
|
| AudioFileFormat::MP4_256
|
|
| AudioFileFormat::MP4_256_DUAL => Some("audio/mp4"),
|
|
AudioFileFormat::FLAC_FLAC => Some("audio/flac"),
|
|
AudioFileFormat::UNKNOWN_FORMAT => None,
|
|
}
|
|
}
|
|
|
|
/// Get the bitrate of the audio format in kbit/s
|
|
pub fn audio_format_bitrate(format: AudioFileFormat) -> Option<u32> {
|
|
match format {
|
|
AudioFileFormat::OGG_VORBIS_96 | AudioFileFormat::MP3_96 => Some(96000),
|
|
AudioFileFormat::OGG_VORBIS_160
|
|
| AudioFileFormat::MP3_160
|
|
| AudioFileFormat::MP3_160_ENC => Some(160000),
|
|
AudioFileFormat::OGG_VORBIS_320 | AudioFileFormat::MP3_320 => Some(320000),
|
|
AudioFileFormat::MP4_128 | AudioFileFormat::MP4_128_DUAL => Some(128000),
|
|
AudioFileFormat::MP3_256 | AudioFileFormat::MP4_256 | AudioFileFormat::MP4_256_DUAL => {
|
|
Some(256000)
|
|
}
|
|
AudioFileFormat::AAC_24 => Some(24000),
|
|
AudioFileFormat::AAC_48 => Some(48000),
|
|
AudioFileFormat::FLAC_FLAC | AudioFileFormat::UNKNOWN_FORMAT => None,
|
|
}
|
|
}
|
|
|
|
pub fn audio_format_available(format: AudioFileFormat, is_premium: bool) -> bool {
|
|
match format {
|
|
AudioFileFormat::OGG_VORBIS_96
|
|
| AudioFileFormat::OGG_VORBIS_160
|
|
| AudioFileFormat::MP3_160
|
|
| AudioFileFormat::MP3_96
|
|
| AudioFileFormat::MP3_160_ENC
|
|
| AudioFileFormat::AAC_24
|
|
| AudioFileFormat::AAC_48
|
|
| AudioFileFormat::MP4_128
|
|
| AudioFileFormat::MP4_128_DUAL => true,
|
|
AudioFileFormat::OGG_VORBIS_320
|
|
| AudioFileFormat::MP3_256
|
|
| AudioFileFormat::MP3_320
|
|
| AudioFileFormat::MP4_256
|
|
| AudioFileFormat::MP4_256_DUAL
|
|
| AudioFileFormat::FLAC_FLAC => is_premium,
|
|
AudioFileFormat::UNKNOWN_FORMAT => false,
|
|
}
|
|
}
|
|
|
|
/// Return true if the audio format uses Widevine
|
|
pub fn audio_format_widevine(format: AudioFileFormat) -> bool {
|
|
matches!(
|
|
format,
|
|
AudioFileFormat::MP4_128
|
|
| AudioFileFormat::MP4_128_DUAL
|
|
| AudioFileFormat::MP4_256
|
|
| AudioFileFormat::MP4_256_DUAL
|
|
)
|
|
}
|