Skip to content

Commit

Permalink
client_id parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeunig committed Nov 25, 2023
1 parent ba5bae3 commit 6a58ee3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 17 deletions.
35 changes: 27 additions & 8 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use reqwest::header::HeaderMap;


// While creating files, certain characters are not allowed to be in the name, so we use this to delete them
fn sanitize_song_name(input: &str) -> String {
fn sanitize_song_name(input: &str, path: &PathBuf) -> String {
let mut result = input
.replace("\\u0026", "and"); // & -> and
result = result.replace("\\u003c3", "ily"); // <3 -> ily
Expand Down Expand Up @@ -36,7 +36,7 @@ fn regex_get_first(regex: Regex, text: &str) -> Option<String> {

struct ThreadWatcher;

// If the function panics, remove one count from tthe thread count since the thread obviously isn't running
// If the function panics, remove one count from the thread count since the thread obviously isn't running
impl Drop for ThreadWatcher {
fn drop(&mut self) {
if thread::panicking() {
Expand All @@ -50,7 +50,7 @@ use std::thread;
static GLOBAL_THREAD_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);


pub fn prepare_download(songs: Vec<String>, temp_dir: &mut PathBuf, download_dir: &mut PathBuf, threads: usize, is_track: bool) {
pub fn prepare_download(songs: Vec<String>, temp_dir: &mut PathBuf, download_dir: &mut PathBuf, threads: usize, is_track: bool, client_id: String) {
let max_threads = std::sync::atomic::AtomicUsize::new(0);
max_threads.fetch_add(threads, Ordering::SeqCst);
let req: Client = reqwest::blocking::ClientBuilder::new().use_rustls_tls().danger_accept_invalid_certs(true).build().unwrap();
Expand All @@ -64,6 +64,7 @@ pub fn prepare_download(songs: Vec<String>, temp_dir: &mut PathBuf, download_dir
let song_wrapped = Arc::new(Mutex::new(song.clone()));
let temp_dir_wrapped = Arc::new(Mutex::new(temp_dir.clone()));
let download_dir_wrapped = Arc::new(Mutex::new(download_dir.clone()));
let client_id_wrapped = Arc::new(Mutex::new(client_id.clone()));
GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::Relaxed);
logging(Severities::INFO,format!("Downloading {}",&song));
thread::spawn(move || {
Expand All @@ -73,8 +74,9 @@ pub fn prepare_download(songs: Vec<String>, temp_dir: &mut PathBuf, download_dir
let song_locked = song_wrapped.lock().unwrap();
let mut temp_dir_locked = temp_dir_wrapped.lock().unwrap();
let mut download_dir_locked = download_dir_wrapped.lock().unwrap();
let client_id_locked = client_id_wrapped.lock().unwrap();

download(req_locked.clone(), song_locked.to_string(), &mut temp_dir_locked, &mut download_dir_locked, is_track);
download(req_locked.clone(), song_locked.to_string(), &mut temp_dir_locked, &mut download_dir_locked, is_track, &client_id_locked);
GLOBAL_THREAD_COUNT.fetch_sub(1, Ordering::Relaxed);
});
run = false;
Expand Down Expand Up @@ -102,7 +104,7 @@ fn count_mp3(root: PathBuf) -> u32 {
}


fn download(req: Client, song: String, temp_dir: &mut PathBuf, download_dir: &mut PathBuf, is_track: bool) {
fn download(req: Client, song: String, temp_dir: &mut PathBuf, download_dir: &mut PathBuf, is_track: bool, client_id: &str) {
let mut temp_dir = temp_dir.clone().to_owned();
let mut download_dir = download_dir.clone().to_owned();
let mut audio_file_nmbr_count: u32 = 0;
Expand Down Expand Up @@ -265,7 +267,24 @@ fn download(req: Client, song: String, temp_dir: &mut PathBuf, download_dir: &mu
if let Some(hls) = capture.get(1) {
let track_auth = track_auth.as_str();
let hls = hls.as_str();
let r = req.get(format!("{hls}?client_id=baLbCx2miy7TG4nunX9yTWklG3ecgeE9&track_authorization={track_auth}"))
let mut headers = HeaderMap::new();
headers.insert("Accept", "*/*".parse().unwrap());
headers.insert("Accept-Language", "hu-HU,hu;q=0.9".parse().unwrap());
headers.insert("Cache-Control", "no-cache".parse().unwrap());
headers.insert("Connection", "keep-alive".parse().unwrap());
headers.insert("Content-Type", "application/json".parse().unwrap());
headers.insert("Origin", "https://soundcloud.com".parse().unwrap());
headers.insert("Pragma", "no-cache".parse().unwrap());
headers.insert("Referer", "https://soundcloud.com/".parse().unwrap());
headers.insert("Sec-Fetch-Dest", "empty".parse().unwrap());
headers.insert("Sec-Fetch-Mode", "cors".parse().unwrap());
headers.insert("Sec-Fetch-Site", "same-site".parse().unwrap());
headers.insert("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36".parse().unwrap());
headers.insert("sec-ch-ua", "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"".parse().unwrap());
headers.insert("sec-ch-ua-mobile", "?0".parse().unwrap());
headers.insert("sec-ch-ua-platform", "\"Windows\"".parse().unwrap());
let r = req.get(format!("{hls}?client_id={client_id}&track_authorization={track_auth}"))
.headers(headers.clone())
.send().unwrap();
if !r.status().is_success() {
logging(Severities::ERROR, format!("Expected status code 200, got status code {} on song : {}",r.status(),&song));
Expand All @@ -276,7 +295,7 @@ fn download(req: Client, song: String, temp_dir: &mut PathBuf, download_dir: &mu
logging(Severities::ERROR, format!("No download link found on song : {} | If this issue persists, please contact the developer",&song));
return;
}
let r = req.get(&r[8..r.len()-2]).send().unwrap().text().unwrap();
let r = req.get(&r[8..r.len()-2]).headers(headers).send().unwrap().text().unwrap();
let re = Regex::new(r#"(https://cf-hls-media.sndcdn.com/media/.*?)\n"#).unwrap();
let links = re.captures_iter(&r);

Expand All @@ -301,7 +320,7 @@ fn download(req: Client, song: String, temp_dir: &mut PathBuf, download_dir: &mu
}
// mp3cat magic
let mut arguments: Vec<String> = Vec::new();
download_dir.push(format!("{}.mp3",sanitize_song_name(&song_name)));
download_dir.push(format!("{}.mp3",sanitize_song_name(&song_name, &download_dir)));

let mut audio = 0;
while audio < audio_file_nmbr_count {
Expand Down
26 changes: 17 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ use crate::logging::logging;
mod download;
mod logging;

fn get_client_id() -> String {
let req = reqwest::blocking::get("https://a-v2.sndcdn.com/assets/0-79b49120.js").unwrap().text().unwrap();
let re = regex::Regex::new(r#"client_id:"(.*?)""#).unwrap();
let r = re.captures(&req).unwrap().get(0).unwrap().as_str();
r[11..r.len()-1].to_owned()
}

fn additional_argument_helper(args: &Vec<String>) -> (PathBuf,PathBuf) {
let mut temp_dir: PathBuf = env::temp_dir();
let mut download_dir: PathBuf = Path::new("./").to_path_buf();
Expand Down Expand Up @@ -90,7 +97,7 @@ fn trimming(track: String) -> String {
splitted.get(0).unwrap().to_string()
}

fn playlist_to_vec(req: reqwest::blocking::Client, dest: &mut Vec<String>, orig: Vec<String>) {
fn playlist_to_vec(req: reqwest::blocking::Client, dest: &mut Vec<String>, orig: Vec<String>, client_id: &str) {
// orig -> track ids
use reqwest::header::HeaderMap;
use regex::Regex;
Expand Down Expand Up @@ -119,7 +126,7 @@ fn playlist_to_vec(req: reqwest::blocking::Client, dest: &mut Vec<String>, orig:
original.remove(0);
temp = temp + 1;
if temp == 10 {
url.push_str("&client_id=0nr4Ys43jAqfn0VkGXfxTWh9d4NB0o54&[object Object]=&app_version=1694501791&app_locale=en");
url.push_str(&format!("&client_id={client_id}&[object Object]=&app_version=1694501791&app_locale=en"));
let r = req.get(url).headers(headers.clone()).send().unwrap().text().unwrap();
for capture in reg.captures_iter(&r).map(|c| c.get(1)) {
dest.push(capture.unwrap().as_str().to_string());
Expand All @@ -128,7 +135,7 @@ fn playlist_to_vec(req: reqwest::blocking::Client, dest: &mut Vec<String>, orig:
temp = 0;
}
}
url.push_str("&client_id=0nr4Ys43jAqfn0VkGXfxTWh9d4NB0o54&[object Object]=&app_version=1694501791&app_locale=en");
url.push_str(&format!("&client_id={client_id}&[object Object]=&app_version=1694501791&app_locale=en"));
let r = req.get(url).headers(headers.clone()).send().unwrap().text().unwrap();
for capture in reg.captures_iter(&r).map(|c| c.get(1)) {
dest.push(capture.unwrap().as_str().to_string());
Expand All @@ -141,6 +148,7 @@ fn main() {
check_for_invalid_arguments(&args);
let mut paths = additional_argument_helper(&args);
paths.0.push("SCDownloader");
let client_id: String = get_client_id();
// We're safe the unwrap the args because we checked if the argument list of valid
match args.get(1).unwrap().as_str() {
"track" => {
Expand All @@ -155,7 +163,7 @@ fn main() {
}
let mut list: Vec<String> = Vec::new();
list.push(trimming(arg2));
prepare_download(list, &mut paths.0, &mut paths.1, 1, true);
prepare_download(list, &mut paths.0, &mut paths.1, 1, true, client_id);
},
"playlist" | "album" => {
let mut arg2 = args.get(2).unwrap().to_owned();
Expand Down Expand Up @@ -197,8 +205,8 @@ fn main() {
}
}
let mut songs: Vec<String> = Vec::new();
playlist_to_vec(req, &mut songs, list);
prepare_download(songs, &mut paths.0, &mut paths.1, 3, false);
playlist_to_vec(req, &mut songs, list, &client_id);
prepare_download(songs, &mut paths.0, &mut paths.1, 3, false, client_id);
},
"artist" => {
use regex::Regex;
Expand Down Expand Up @@ -230,10 +238,10 @@ fn main() {
headers.insert("Sec-Fetch-User", "?1".parse().unwrap());
headers.insert("Sec-GPC", "1".parse().unwrap());
headers.insert("Connection", "keep-alive".parse().unwrap());
let r = req.get(format!("https://soundcloud.com/{}",arg2)).headers(headers).send().unwrap().text().unwrap();
let r = req.get(format!("https://soundcloud.com/{}",arg2)).headers(headers.clone()).send().unwrap().text().unwrap();
let reg = Regex::new(r#"content="soundcloud://users:([0-9]*?)""#).unwrap();
let uid = reg.captures(&r).unwrap().get(1).unwrap().as_str().to_owned();
let r = req.get(format!("https://api-v2.soundcloud.com/users/{}/tracks?offset=0&limit=79999&representation=&client_id=TtbhBUaHqao06g1mUwVTxbjj8TSUkiCl&app_version=1694761046&app_locale=en",uid)).send().unwrap().text().unwrap();
let r = req.get(format!("https://api-v2.soundcloud.com/users/{}/tracks?offset=0&limit=79999&representation=&client_id={client_id}&app_version=1694761046&app_locale=en",uid)).headers(headers).send().unwrap().text().unwrap();
let reg = Regex::new(r#""permalink_url":"https://soundcloud\.com/((?:[a-zA-Z0-9-_]*?)/(?:[a-zA-Z0-9-_]*?))""#).unwrap();
let mut list: Vec<String> = Vec::new();
for a in reg.captures_iter(&r).map(|c| c.get(1)) {
Expand All @@ -245,7 +253,7 @@ fn main() {
}
}
std::thread::sleep(std::time::Duration::from_secs(5));
prepare_download(list, &mut paths.0, &mut paths.1, 3, false);
prepare_download(list, &mut paths.0, &mut paths.1, 3, false, client_id);
},
_ => {
exit(0);
Expand Down

0 comments on commit 6a58ee3

Please sign in to comment.