feat: redirect secondary YT channels to the YTM channel

Squashed commit of the following:

commit 88809265ead6eadfafab4b74091dd1af357b9577
Author: ThetaDev <t.testboy@gmail.com>
Date:   Sat Jan 21 22:16:23 2023 +0100

    feat: redirect secondary YT channels to the YTM channel

commit 02cc120912509f40f45da243ba5d37798b9ff411
Author: ThetaDev <t.testboy@gmail.com>
Date:   Mon Jan 9 23:57:18 2023 +0100

    add artists_no_tracks testfile
This commit is contained in:
ThetaDev 2023-01-21 22:18:25 +01:00
parent f44bc6434a
commit a706a7011b
11 changed files with 13543 additions and 23 deletions

View file

@ -4,7 +4,7 @@ mod protobuf;
pub mod dictionary;
pub use date::{month_from_n, now_sec, shift_months, shift_years};
pub use protobuf::ProtoBuilder;
pub use protobuf::{string_from_pb, ProtoBuilder};
use std::{
borrow::{Borrow, Cow},
@ -89,12 +89,6 @@ pub fn url_to_params(url: &str) -> Result<(Url, BTreeMap<String, String>), Error
Ok((parsed_url, url_params))
}
pub fn urlencode(string: &str) -> String {
url::form_urlencoded::Serializer::new(String::new())
.append_key_only(string)
.finish()
}
/// Parse a string after removing all non-numeric characters
pub fn parse_numeric<F>(string: &str) -> Result<F, F::Err>
where

View file

@ -54,3 +54,85 @@ impl ProtoBuilder {
self.bytes.append(&mut pb.bytes);
}
}
fn parse_varint<P: Iterator<Item = u8>>(pb: &mut P) -> Option<u64> {
let mut result = 0;
let mut num_read = 0;
for b in pb.by_ref() {
let value = b & 0x7f;
result |= (value as u64) << (7 * num_read);
num_read += 1;
if b & 0x80 == 0 {
break;
}
}
if num_read == 0 {
None
} else {
Some(result)
}
}
fn parse_field<P: Iterator<Item = u8>>(pb: &mut P) -> Option<(u32, u8)> {
parse_varint(pb).map(|v| {
let f = (v >> 3) as u32;
let w = (v & 0x07) as u8;
(f, w)
})
}
pub fn string_from_pb<P: IntoIterator<Item = u8>>(pb: P, field: u32) -> Option<String> {
let mut pb = pb.into_iter();
while let Some((this_field, wire)) = parse_field(&mut pb) {
let to_skip = match wire {
// varint
0 => {
parse_varint(&mut pb);
0
}
// fixed 64bit
1 => 8,
// fixed 32bit
5 => 4,
// string
2 => {
let len = some_or_bail!(parse_varint(&mut pb), None);
if this_field == field {
let mut buf = Vec::new();
for _ in 0..len {
buf.push(some_or_bail!(pb.next(), None));
}
return String::from_utf8(buf).ok();
} else {
len
}
}
_ => return None,
};
for _ in 0..to_skip {
pb.next();
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
// #[test]
// fn t_parse_varint() {
// }
#[test]
fn t_parse_proto() {
let p = "GhhVQzl2cnZOU0wzeGNXR1NrVjg2UkVCU2c%3D";
let p_bytes = base64::decode(urlencoding::decode(p).unwrap().as_bytes()).unwrap();
let res = string_from_pb(p_bytes, 3).unwrap();
assert_eq!(res, "UC9vrvNSL3xcWGSkV86REBSg");
}
}