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:
parent
f44bc6434a
commit
a706a7011b
11 changed files with 13543 additions and 23 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue