Compare commits

...
Sign in to create a new pull request.

64 commits

Author SHA1 Message Date
6035e6db4e
fix: parse channel subscriber/video count correctly 2025-06-18 15:35:47 +02:00
e7e389a316
feat: add unavailable field for music tracks
fix: handling albums with unavailable tracks
2025-06-18 15:34:05 +02:00
412cd37840
test: fix isrc_search_languages (use quoted query) 2025-06-18 13:25:13 +02:00
ta3pks
71712e4eda remove unwrap trying to fetch visitor data (#60)
Co-authored-by: nikos efthias <nikos@mugsoft.io>
Reviewed-on: https://codeberg.org/ThetaDev/rustypipe/pulls/60
Co-authored-by: ta3pks <ta3pks@noreply.codeberg.org>
Co-committed-by: ta3pks <ta3pks@noreply.codeberg.org>
2025-06-17 13:29:52 +02:00
1f4c9c85b9
chore(release): release rustypipe v0.11.4 2025-04-23 21:30:33 +02:00
f0477ea3a9
test: add sig deobf test case 2025-04-23 21:29:51 +02:00
be6da5e7e3
feat: player: handle VPN ban and captcha required error messages 2025-04-23 21:21:23 +02:00
d675987654
fix: deobfuscator: handle 1-char long global variables, find nsig fn (player 6450230e) 2025-04-23 17:22:22 +02:00
c6abd89087
test: fix tests 2025-04-18 16:38:44 +02:00
703f350b6b
chore(release): release rustypipe v0.11.3 2025-04-03 13:39:28 +02:00
af415ddf8f chore(deps): update rust crate rand to 0.9.0 2025-04-03 11:08:18 +00:00
daf3d035be
fix: handle music artist not found 2025-03-31 18:11:14 +02:00
187bf1c9a0
fix: switch client if no adaptive stream URLs were returned 2025-03-26 02:44:08 +01:00
ea80717f69
fix: handle music playlist/album not found 2025-03-26 02:35:03 +01:00
939a7aea61
fix: deobfuscator: handle global functions as well 2025-03-26 02:12:18 +01:00
47bea4eed2
test: update music_artist_basic snapshot 2025-03-26 01:38:35 +01:00
189ba81a42
fix: extractor: small simplification 2025-03-26 01:38:12 +01:00
ac44e95a88
fix: extractor: global variable extraction fixed 2025-03-26 01:20:35 +01:00
23c8775326
chore(release): release rustypipe v0.11.2 2025-03-24 01:50:53 +01:00
07db7b1166
fix: handle player returning no adaptive stream URLs 2025-03-24 01:28:07 +01:00
4ce6746be5
fix: extract deobf data with global strings variable 2025-03-24 01:12:01 +01:00
e8acbfbbcf
fix: A/B test 22: commandExecutorCommand for playlist continuations 2025-03-16 19:45:14 +01:00
fcf27aa3b2
chore(release): release rustypipe-cli v0.7.2 2025-03-16 18:20:32 +01:00
64ed3b14e3
chore(release): release rustypipe v0.11.1 2025-03-16 18:13:55 +01:00
63a6f50a8b
fix: always skip failed clients 2025-03-16 16:51:43 +01:00
8342caeb0f
fix: desktop client: generate PO token from user_syncid when authenticated 2025-03-16 01:56:29 +01:00
c04b60604d
fix: simplify get_player_from_clients logic 2025-03-16 01:24:54 +01:00
2f18efa1cf
fix: log download URL 2025-03-16 01:21:29 +01:00
b8f61c9bae
test: skip android client test 2025-03-04 22:50:33 +01:00
9ed1306f3a
chore(deps): update rust crate rstest to 0.25.0 2025-03-04 22:48:10 +01:00
6d481c16d0
update smartcrop2 to v0.4.0, remove black borders from album covers 2025-03-04 22:38:01 +01:00
144a670da1
chore(release): release rustypipe-cli v0.7.1 2025-02-26 19:48:12 +01:00
035c07f170
chore(deps): update rustypipe to 0.11.0 2025-02-26 19:47:42 +01:00
9bfd3ee1ba
chore(release): release rustypipe-downloader v0.3.1 2025-02-26 19:45:43 +01:00
1adcb12932
chore(release): release rustypipe v0.11.0 2025-02-26 19:41:36 +01:00
e7ef067f43
small doc fix 2025-02-26 19:40:10 +01:00
f3057b4d63
chore: remove commented-out debug statements 2025-02-26 19:32:46 +01:00
6737512f5f
fix: A/B test 21: music album recommendations 2025-02-26 15:21:47 +01:00
544782f8de
feat: add original album track count, fix fetching albums with more than 200 tracks 2025-02-26 15:21:47 +01:00
83f8652776 ci: disable renovate 2025-02-22 23:02:15 +00:00
739eac4d1f
test: fix tests 2025-02-18 00:16:09 +01:00
4d60e64f2c
ci: remove workflow_dispatch trigger 2025-02-09 04:35:30 +01:00
45d3a9cd33
ci: add CLI release files 2025-02-09 03:57:13 +01:00
f8a0a253cc
change line in downloader changelog 2025-02-09 03:15:30 +01:00
8933c6fa2a
chore(release): release rustypipe-cli v0.7.0 2025-02-09 03:14:30 +01:00
629b5905da
feat: add verbose flag 2025-02-09 03:09:47 +01:00
26e0c2cb2b
chore(release): release rustypipe-downloader v0.3.0 2025-02-09 02:53:59 +01:00
fb1b732d56
chore(release): release rustypipe v0.10.0 2025-02-09 02:32:44 +01:00
80a358ee54
Revert "refactor!: rename n_http_retries option to n_request_attempts to be less misleading"
This reverts commit b8cfe1b034.
2025-02-09 02:20:55 +01:00
c0770f281c
ci: release rustypipe-cli binaries 2025-02-09 02:01:27 +01:00
1d755b76bf
feat: add RustyPipe::version_botguard fn, detect rustypipe-botguard in current dir, add botguard version to report 2025-02-09 01:52:09 +01:00
9957add2b5
doc: add Botguard info to README 2025-02-07 23:15:34 +01:00
c1a872e1c1
refactor: rename rustypipe-cli binary name to rustypipe 2025-02-07 22:50:56 +01:00
0c94267d03
fix: only use cached potokens with min. 10min lifetime 2025-02-07 22:01:59 +01:00
a80f046a19
ci: update rustypipe-botguard 2025-02-07 20:46:33 +01:00
65cb4244c6
feat!: add userdata feature for all personal data queries (playback history, subscriptions) 2025-02-07 13:21:12 +01:00
c87bac1856
shorten CLI timezone flags, add docs 2025-02-07 04:13:45 +01:00
9890538c0e
reorganize time-tz dependency 2025-02-07 04:13:45 +01:00
5acbf0e456
fix: use localzone crate to get local tz 2025-02-07 04:13:44 +01:00
34f8e9b551
fix: compile error on windows 2025-02-07 04:13:44 +01:00
4f2bb47ab4
feat: add --timezone-local CLI option 2025-02-07 04:13:44 +01:00
a5a7be5b4e
fix: correct timezone offset for parsed dates, add timezone_local option 2025-02-07 04:13:44 +01:00
3a2370b97c
feat: add timezone query option 2025-02-07 04:13:43 +01:00
ccb1178b95
fix iOS client doc 2025-02-07 04:13:39 +01:00
130 changed files with 49475 additions and 863 deletions

View file

@ -28,17 +28,22 @@ jobs:
run: | run: |
TARGET=$(rustc --version --verbose | grep "host:" | sed -e 's/^host: //') TARGET=$(rustc --version --verbose | grep "host:" | sed -e 's/^host: //')
cd ~ cd ~
curl -SsL -o rustypipe-botguard.tar.xz "https://codeberg.org/ThetaDev/rustypipe-botguard/releases/download/v0.1.0/rustypipe-botguard-v0.1.0-${TARGET}.tar.xz" curl -SsL -o rustypipe-botguard.tar.xz "https://codeberg.org/ThetaDev/rustypipe-botguard/releases/download/v0.1.1/rustypipe-botguard-v0.1.1-${TARGET}.tar.xz"
cd /usr/local/bin cd /usr/local/bin
sudo tar -xJf ~/rustypipe-botguard.tar.xz sudo tar -xJf ~/rustypipe-botguard.tar.xz
rm ~/rustypipe-botguard.tar.xz rm ~/rustypipe-botguard.tar.xz
rustypipe-botguard --version rustypipe-botguard --version
- name: 📎 Clippy - name: 📎 Clippy
run: cargo clippy --all --tests --features=rss,indicatif,audiotag -- -D warnings run: |
cargo clippy --all --tests --features=rss,userdata,indicatif,audiotag -- -D warnings
cargo clippy --package=rustypipe --tests -- -D warnings
cargo clippy --package=rustypipe-downloader -- -D warnings
cargo clippy --package=rustypipe-cli -- -D warnings
cargo clippy --package=rustypipe-cli --features=timezone -- -D warnings
- name: 🧪 Test - name: 🧪 Test
run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --retries 2 --features rss --workspace -- --skip 'cookie_auth::' run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --retries 2 --features rss,userdata --workspace -- --skip 'user_data::'
env: env:
ALL_PROXY: "http://warpproxy:8124" ALL_PROXY: "http://warpproxy:8124"

View file

@ -0,0 +1,69 @@
name: Release CLI
on:
push:
tags:
- "rustypipe-cli/v*.*.*"
jobs:
Release:
runs-on: cimaster-latest
steps:
- name: 📦 Checkout repository
uses: actions/checkout@v4
- name: Setup cross compilation
run: |
rustup target add x86_64-pc-windows-msvc x86_64-apple-darwin aarch64-apple-darwin
cargo install cargo-xwin
# https://wapl.es/rust/2019/02/17/rust-cross-compile-linux-to-macos.html/
sudo apt-get install -y llvm clang cmake
cd ~
git clone https://github.com/tpoechtrager/osxcross
cd osxcross
wget -nc "https://github.com/joseluisq/macosx-sdks/releases/download/12.3/MacOSX12.3.sdk.tar.xz"
mv MacOSX12.3.sdk.tar.xz tarballs/
UNATTENDED=yes OSX_VERSION_MIN=12.3 ./build.sh
OSXCROSS_BIN="$(pwd)/target/bin"
echo "CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER=$(find "$OSXCROSS_BIN" -name "x86_64-apple-darwin*-clang")" >> $GITHUB_ENV
echo "CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS=-Car=$(find "$OSXCROSS_BIN" -name "x86_64-apple-darwin*-ar"),-Clink-arg=-undefined,-Clink-arg=dynamic_lookup" >> $GITHUB_ENV
echo "CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=$(find "$OSXCROSS_BIN" -name "aarch64-apple-darwin*-clang")" >> $GITHUB_ENV
echo "CARGO_TARGET_AARCH64_APPLE_DARWIN_RUSTFLAGS=-Car=$(find "$OSXCROSS_BIN" -name "aarch64-apple-darwin*-ar"),-Clink-arg=-undefined,-Clink-arg=dynamic_lookup" >> $GITHUB_ENV
- name: ⚒️ Build application
run: |
export PATH="$PATH:$HOME/osxcross/target/bin"
CRATE="rustypipe-cli"
PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-linux-gnu cargo build --release --package=$CRATE --target x86_64-unknown-linux-gnu
PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu cargo build --release --package=$CRATE --target aarch64-unknown-linux-gnu
CC="$CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER" CXX="$CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER++" cargo build --release --package=$CRATE --target x86_64-apple-darwin
CC="$CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER" CXX="$CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER++" cargo build --release --package=$CRATE --target aarch64-apple-darwin
cargo xwin build --release --package=$CRATE --target x86_64-pc-windows-msvc
- name: Prepare release
run: |
CRATE="rustypipe-cli"
BIN="rustypipe"
echo "CRATE=$CRATE" >> "$GITHUB_ENV"
echo "CRATE_VERSION=$(echo '${{ github.ref_name }}' | awk 'BEGIN{RS="/"} NR==2{print}')" >> "$GITHUB_ENV"
CL_PATH="cli/CHANGELOG.md"
{
echo 'CHANGELOG<<END_OF_FILE'
awk 'BEGIN{RS="(^|\n)## [^\n]+\n*"} NR==2 { print }' "$CL_PATH"
echo END_OF_FILE
} >> "$GITHUB_ENV"
mkdir dist
for arch in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu x86_64-apple-darwin aarch64-apple-darwin; do
tar -cJf "dist/${BIN}-${CRATE_VERSION}-${arch}.tar.xz" -C target/${arch}/release "${BIN}"
done
(cd target/x86_64-pc-windows-msvc/release && zip -9 "../../../dist/${BIN}-${CRATE_VERSION}-x86_64-pc-windows-msvc.zip" "${BIN}.exe")
- name: 🎉 Publish release
uses: https://gitea.com/actions/release-action@main
with:
title: "${{ env.CRATE }} ${{ env.CRATE_VERSION }}"
body: "${{ env.CHANGELOG }}"
files: dist/*

View file

@ -10,4 +10,8 @@ repos:
hooks: hooks:
- id: cargo-fmt - id: cargo-fmt
- id: cargo-clippy - id: cargo-clippy
args: ["--all", "--tests", "--features=rss,indicatif,audiotag", "--", "-D", "warnings"] name: cargo-clippy rustypipe
args: ["--package=rustypipe", "--tests", "--", "-D", "warnings"]
- id: cargo-clippy
name: cargo-clippy workspace
args: ["--all", "--tests", "--features=rss,userdata,indicatif,audiotag", "--", "-D", "warnings"]

View file

@ -1,10 +0,0 @@
steps:
test:
image: rust:latest
environment:
- CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
commands:
- rustup component add rustfmt clippy
- cargo fmt --all --check
- cargo clippy --all --features=rss -- -D warnings
- cargo test --features=rss --workspace

View file

@ -3,6 +3,104 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [v0.11.4](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.11.3..rustypipe/v0.11.4) - 2025-04-23
### 🚀 Features
- Player: handle VPN ban and captcha required error messages - ([be6da5e](https://codeberg.org/ThetaDev/rustypipe/commit/be6da5e7e3558ef39773bf45bcb8afbf006bacec))
### 🐛 Bug Fixes
- Deobfuscator: handle 1-char long global variables, find nsig fn (player 6450230e) - ([d675987](https://codeberg.org/ThetaDev/rustypipe/commit/d675987654972c6aa4cc2b291d25bc49fa60173e))
## [v0.11.3](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.11.2..rustypipe/v0.11.3) - 2025-04-03
### 🐛 Bug Fixes
- Deobfuscator: global variable extraction fixed - ([ac44e95](https://codeberg.org/ThetaDev/rustypipe/commit/ac44e95a88d95f9d2d1ec672f86ca9d31d6991b9))
- Deobfuscator: small simplification - ([189ba81](https://codeberg.org/ThetaDev/rustypipe/commit/189ba81a42e6c09f6af4d2768c449c22b864101e))
- Deobfuscator: handle global functions as well - ([939a7ae](https://codeberg.org/ThetaDev/rustypipe/commit/939a7aea61a3eee4c1e67bfbfc835f0ce3934171))
- Handle music playlist/album not found - ([ea80717](https://codeberg.org/ThetaDev/rustypipe/commit/ea80717f692b2c45b5063c362c9fa8ebca5a3471))
- Switch client if no adaptive stream URLs were returned - ([187bf1c](https://codeberg.org/ThetaDev/rustypipe/commit/187bf1c9a0e846bff205e0d71a19c5a1ce7b1943))
- Handle music artist not found - ([daf3d03](https://codeberg.org/ThetaDev/rustypipe/commit/daf3d035be38b59aef1ae205ac91c2bbdda2fe66))
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rust crate rand to 0.9.0 - ([af415dd](https://codeberg.org/ThetaDev/rustypipe/commit/af415ddf8f94f00edb918f271d8e6336503e9faf))
## [v0.11.2](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.11.1..rustypipe/v0.11.2) - 2025-03-24
### 🐛 Bug Fixes
- A/B test 22: commandExecutorCommand for playlist continuations - ([e8acbfb](https://codeberg.org/ThetaDev/rustypipe/commit/e8acbfbbcf5d31b5ac34410ddf334e5534e3762f))
- Extract deobf data with global strings variable - ([4ce6746](https://codeberg.org/ThetaDev/rustypipe/commit/4ce6746be538564e79f7e3c67d7a91aaa53f48ea))
- Handle player returning no adaptive stream URLs - ([07db7b1](https://codeberg.org/ThetaDev/rustypipe/commit/07db7b1166e912e1554f98f2ae20c2c356fed38f))
## [v0.11.1](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.11.0..rustypipe/v0.11.1) - 2025-03-16
### 🐛 Bug Fixes
- Simplify get_player_from_clients logic - ([c04b606](https://codeberg.org/ThetaDev/rustypipe/commit/c04b60604d2628bf8f0e3de453c243adbb966e57))
- Desktop client: generate PO token from user_syncid when authenticated - ([8342cae](https://codeberg.org/ThetaDev/rustypipe/commit/8342caeb0f566a38060a6ec69f3ca65b9a2afcd6))
- Always skip failed clients - ([63a6f50](https://codeberg.org/ThetaDev/rustypipe/commit/63a6f50a8b5ad6bb984282335c1481ae3cd2fe83))
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rust crate rstest to 0.25.0 - ([9ed1306](https://codeberg.org/ThetaDev/rustypipe/commit/9ed1306f3aaeb993c409997ddfbc47499e4f4d22))
## [v0.11.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.10.0..rustypipe/v0.11.0) - 2025-02-26
### 🚀 Features
- Add original album track count, fix fetching albums with more than 200 tracks - ([544782f](https://codeberg.org/ThetaDev/rustypipe/commit/544782f8de728cda0aca9a1cb95837cdfbd001f1))
### 🐛 Bug Fixes
- A/B test 21: music album recommendations - ([6737512](https://codeberg.org/ThetaDev/rustypipe/commit/6737512f5f67c8cd05d4552dd0e0f24381035b35))
## [v0.10.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.9.0..rustypipe/v0.10.0) - 2025-02-09
### 🚀 Features
- Add visitor data cache, remove random visitor data - ([b12f4c5](https://codeberg.org/ThetaDev/rustypipe/commit/b12f4c5d821a9189d7ed8410ad860824b6d052ef))
- Add support for rustypipe-botguard to get PO tokens - ([b90a252](https://codeberg.org/ThetaDev/rustypipe/commit/b90a252a5e1bf05a5294168b0ec16a73cbb88f42))
- Add session po token cache - ([b72b501](https://codeberg.org/ThetaDev/rustypipe/commit/b72b501b6dbcf4333b24cd80e7c8c61b0c21ec91))
- Check rustypipe-botguard-api version - ([8385b87](https://codeberg.org/ThetaDev/rustypipe/commit/8385b87c63677f32a240679a78702f53072e517a))
- Rewrite request attempt system, retry with different visitor data - ([dfd03ed](https://codeberg.org/ThetaDev/rustypipe/commit/dfd03edfadff2657e9cfbf04e5d313ba409520ac))
- Log failed player fetch attempts with player_from_clients - ([8e35358](https://codeberg.org/ThetaDev/rustypipe/commit/8e35358c8941301f6ebf7646a11ab22711082569))
- Add timezone query option - ([3a2370b](https://codeberg.org/ThetaDev/rustypipe/commit/3a2370b97ca3d0f40d72d66a23295557317d29fb))
- [**breaking**] Add userdata feature for all personal data queries (playback history, subscriptions) - ([65cb424](https://codeberg.org/ThetaDev/rustypipe/commit/65cb4244c6ab547f53d0cb12af802c4189188c86))
- Add RustyPipe::version_botguard fn, detect rustypipe-botguard in current dir, add botguard version to report - ([1d755b7](https://codeberg.org/ThetaDev/rustypipe/commit/1d755b76bf4569f7d0bb90a65494ac8e7aae499a))
### 🐛 Bug Fixes
- Parsing history dates - ([af7dc10](https://codeberg.org/ThetaDev/rustypipe/commit/af7dc1016322a87dd8fec0b739939c2b12b6f400))
- A/V streams incorrectly recognized as video-only - ([2b891ca](https://codeberg.org/ThetaDev/rustypipe/commit/2b891ca0788f91f16dbb9203191cb3d2092ecc74))
- Update iOS client - ([e915416](https://codeberg.org/ThetaDev/rustypipe/commit/e91541629d6c944c1001f5883e3c1264aeeb3969))
- A/B test 20: music continuation item renderer - ([9c67f8f](https://codeberg.org/ThetaDev/rustypipe/commit/9c67f8f85bef8214848dc9d17bff6cff252e015e))
- Include whole request body in report - ([15245c1](https://codeberg.org/ThetaDev/rustypipe/commit/15245c18b584e42523762b94fcc7284d483660a0))
- Extracting nsig fn when outside variable starts with $ - ([eda16e3](https://codeberg.org/ThetaDev/rustypipe/commit/eda16e378730a3b57c4982a626df1622a93c574a))
- Retry updating deobf data after a RustyPipe update - ([50ab1f7](https://codeberg.org/ThetaDev/rustypipe/commit/50ab1f7a5d8aeaa3720264b4a4b27805bb0e8121))
- Allow player data to be fetched without botguard - ([29c854b](https://codeberg.org/ThetaDev/rustypipe/commit/29c854b20d7a6677415b1744e7ba7ecd4f594ea5))
- Output full request body in reports, clean up `get_player_po_token` - ([a0d850f](https://codeberg.org/ThetaDev/rustypipe/commit/a0d850f8e01428a73bbd66397d0dbf797b45958f))
- Correct timezone offset for parsed dates, add timezone_local option - ([a5a7be5](https://codeberg.org/ThetaDev/rustypipe/commit/a5a7be5b4e0a0b73d7e1dc802ebd7bd48dafc76d))
- Use localzone crate to get local tz - ([5acbf0e](https://codeberg.org/ThetaDev/rustypipe/commit/5acbf0e456b1f10707e0a56125d993a8129eee3a))
- Only use cached potokens with min. 10min lifetime - ([0c94267](https://codeberg.org/ThetaDev/rustypipe/commit/0c94267d0371b2b26c7b5c9abfa156d5cde2153e))
### 📚 Documentation
- Add Botguard info to README - ([9957add](https://codeberg.org/ThetaDev/rustypipe/commit/9957add2b5d6391b2c1869d2019fd7dd91b8cd41))
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rust crate rquickjs to 0.9.0 (#33) - ([2c8ac41](https://codeberg.org/ThetaDev/rustypipe/commit/2c8ac410aa535d83f8bcc7181f81914b13bceb77))
## [v0.9.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.8.0..rustypipe/v0.9.0) - 2025-01-16 ## [v0.9.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe/v0.8.0..rustypipe/v0.9.0) - 2025-01-16
### 🚀 Features ### 🚀 Features

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rustypipe" name = "rustypipe"
version = "0.9.0" version = "0.11.4"
rust-version = "1.67.1" rust-version = "1.67.1"
edition.workspace = true edition.workspace = true
authors.workspace = true authors.workspace = true
@ -40,11 +40,12 @@ serde_with = { version = "3.0.0", default-features = false, features = [
] } ] }
serde_plain = "1.0.0" serde_plain = "1.0.0"
sha1 = "0.10.0" sha1 = "0.10.0"
rand = "0.8.0" rand = "0.9.0"
time = { version = "0.3.37", features = [ time = { version = "0.3.37", features = [
"macros", "macros",
"serde-human-readable", "serde-human-readable",
"serde-well-known", "serde-well-known",
"local-offset",
] } ] }
futures-util = "0.3.31" futures-util = "0.3.31"
ress = "0.11.0" ress = "0.11.0"
@ -54,6 +55,7 @@ data-encoding = "2.0.0"
urlencoding = "2.1.0" urlencoding = "2.1.0"
quick-xml = { version = "0.37.0", features = ["serialize"] } quick-xml = { version = "0.37.0", features = ["serialize"] }
tracing = { version = "0.1.0", features = ["log"] } tracing = { version = "0.1.0", features = ["log"] }
localzone = "0.3.1"
# CLI # CLI
indicatif = "0.17.0" indicatif = "0.17.0"
@ -65,15 +67,15 @@ dirs = "6.0.0"
filenamify = "0.1.0" filenamify = "0.1.0"
# Testing # Testing
rstest = "0.24.0" rstest = "0.25.0"
tokio-test = "0.4.2" tokio-test = "0.4.2"
insta = { version = "1.17.1", features = ["ron", "redactions"] } insta = { version = "1.17.1", features = ["ron", "redactions"] }
path_macro = "1.0.0" path_macro = "1.0.0"
tracing-test = "0.2.5" tracing-test = "0.2.5"
# Included crates # Included crates
rustypipe = { path = ".", version = "0.9.0", default-features = false } rustypipe = { path = ".", version = "0.11.4", default-features = false }
rustypipe-downloader = { path = "./downloader", version = "0.2.1", default-features = false, features = [ rustypipe-downloader = { path = "./downloader", version = "0.3.1", default-features = false, features = [
"indicatif", "indicatif",
"audiotag", "audiotag",
] } ] }
@ -82,6 +84,7 @@ rustypipe-downloader = { path = "./downloader", version = "0.2.1", default-featu
default = ["default-tls"] default = ["default-tls"]
rss = ["dep:quick-xml"] rss = ["dep:quick-xml"]
userdata = []
# Reqwest TLS options # Reqwest TLS options
default-tls = ["reqwest/default-tls"] default-tls = ["reqwest/default-tls"]
@ -112,6 +115,7 @@ phf.workspace = true
data-encoding.workspace = true data-encoding.workspace = true
urlencoding.workspace = true urlencoding.workspace = true
tracing.workspace = true tracing.workspace = true
localzone.workspace = true
quick-xml = { workspace = true, optional = true } quick-xml = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
@ -123,6 +127,6 @@ tracing-test.workspace = true
[package.metadata.docs.rs] [package.metadata.docs.rs]
# To build locally: # To build locally:
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features rss --no-deps --open # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features rss,userdata --no-deps --open
features = ["rss"] features = ["rss", "userdata"]
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]

View file

@ -1,19 +1,19 @@
test: test:
# cargo test --features=rss # cargo test --features=rss,userdata
cargo nextest run --workspace --features=rss --no-fail-fast --retries 1 -- --skip 'cookie_auth::' cargo nextest run --workspace --features=rss,userdata --no-fail-fast --retries 1 -- --skip 'user_data::'
unittest: unittest:
cargo nextest run --features=rss --no-fail-fast --lib cargo nextest run --features=rss,userdata --no-fail-fast --lib
testyt: testyt:
cargo nextest run --features=rss --no-fail-fast --retries 1 --test youtube -- --skip 'cookie_auth::' cargo nextest run --features=rss,userdata --no-fail-fast --retries 1 --test youtube -- --skip 'user_data::'
testyt-cookie: testyt-cookie:
cargo nextest run --features=rss --no-fail-fast --retries 1 --test youtube cargo nextest run --features=rss,userdata --no-fail-fast --retries 1 --test youtube
testyt-localized: testyt-localized:
YT_LANG=th cargo nextest run --features=rss --no-fail-fast --retries 1 --test youtube -- \ YT_LANG=th cargo nextest run --features=rss,userdata --no-fail-fast --retries 1 --test youtube -- \
--skip 'cookie_auth::' --skip 'search_suggestion' --skip 'isrc_search_languages' --skip 'user_data::' --skip 'search_suggestion' --skip 'isrc_search_languages'
testintl: testintl:
#!/usr/bin/env bash #!/usr/bin/env bash
@ -33,7 +33,7 @@ testintl:
echo "---TESTS FOR $YT_LANG ---" echo "---TESTS FOR $YT_LANG ---"
if YT_LANG="$YT_LANG" cargo nextest run --no-fail-fast --retries 1 --test-threads 4 --test youtube -- \ if YT_LANG="$YT_LANG" cargo nextest run --no-fail-fast --retries 1 --test-threads 4 --test youtube -- \
--skip 'cookie_auth::' --skip 'search_suggestion' --skip 'isrc_search_languages' --skip 'resolve_'; then --skip 'user_data::' --skip 'search_suggestion' --skip 'isrc_search_languages' --skip 'resolve_'; then
echo "--- $YT_LANG COMPLETED ---" echo "--- $YT_LANG COMPLETED ---"
else else
echo "--- $YT_LANG FAILED ---" echo "--- $YT_LANG FAILED ---"

View file

@ -181,6 +181,19 @@ Subscribers: 1780000
... ...
``` ```
## Crate features
Some features of RustyPipe are gated behind features to avoid compiling unneeded
dependencies.
- `rss` Fetch a channel's RSS feed, which is faster than fetching the channel page
- `userdata` Add functions to fetch YouTube user data (watch history, subscriptions,
music library)
You can also choose the TLS library used for making web requests using the same features
as the reqwest crate (`default-tls`, `native-tls`, `native-tls-alpn`,
`native-tls-vendored`, `rustls-tls-webpki-roots`, `rustls-tls-native-roots`).
## Cache storage ## Cache storage
The RustyPipe cache holds the current version numbers for all clients, the JavaScript The RustyPipe cache holds the current version numbers for all clients, the JavaScript
@ -213,6 +226,21 @@ RustyPipe reports come in 3 severity levels:
incomplete) incomplete)
- ERR (entire response could not be deserialized/parsed, RustyPipe returned an error) - ERR (entire response could not be deserialized/parsed, RustyPipe returned an error)
## PO tokens
Since August 2024 YouTube requires PO tokens to access streams from web-based clients
(Desktop, Mobile). Otherwise streams will return a 403 error.
Generating PO tokens requires a simulated browser environment, which would be too large
to include in RustyPipe directly.
Therefore, the PO token generation is handled by a seperate CLI application
([rustypipe-botguard](https://codeberg.org/ThetaDev/rustypipe-botguard)) which is called
by the RustyPipe crate. RustyPipe automatically detects the rustypipe-botguard binary if
it is located in PATH or the current working directory. If your rustypipe-botguard
binary is located at a different path, you can specify it with the `.botguard_bin(path)`
option.
## Authentication ## Authentication
RustyPipe supports authenticating with your YouTube account to access RustyPipe supports authenticating with your YouTube account to access

View file

@ -3,6 +3,52 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [v0.7.2](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-cli/v0.7.1..rustypipe-cli/v0.7.2) - 2025-03-16
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rustypipe to 0.11.1
- *(deps)* Update rustypipe-downloader to 0.3.1
- *(deps)* Update rust crate rstest to 0.25.0 - ([9ed1306](https://codeberg.org/ThetaDev/rustypipe/commit/9ed1306f3aaeb993c409997ddfbc47499e4f4d22))
## [v0.7.1](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-cli/v0.7.0..rustypipe-cli/v0.7.1) - 2025-02-26
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rustypipe to 0.11.0 - ([035c07f](https://codeberg.org/ThetaDev/rustypipe/commit/035c07f170aa293bcc626f27998c2b2b28660881))
## [v0.7.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-cli/v0.6.0..rustypipe-cli/v0.7.0) - 2025-02-09
### 🚀 Features
- Add support for rustypipe-botguard to get PO tokens - ([b90a252](https://codeberg.org/ThetaDev/rustypipe/commit/b90a252a5e1bf05a5294168b0ec16a73cbb88f42))
- [**breaking**] Remove manual PO token options from downloader/cli, add new rustypipe-botguard options - ([cddb32f](https://codeberg.org/ThetaDev/rustypipe/commit/cddb32f190276265258c6ab45b3d43a8891c4b39))
- Add session po token cache - ([b72b501](https://codeberg.org/ThetaDev/rustypipe/commit/b72b501b6dbcf4333b24cd80e7c8c61b0c21ec91))
- Add timezone query option - ([3a2370b](https://codeberg.org/ThetaDev/rustypipe/commit/3a2370b97ca3d0f40d72d66a23295557317d29fb))
- Add --timezone-local CLI option - ([4f2bb47](https://codeberg.org/ThetaDev/rustypipe/commit/4f2bb47ab42ae0c68a64f3b3c2831fa7850b6f56))
- Add verbose flag - ([629b590](https://codeberg.org/ThetaDev/rustypipe/commit/629b5905da653c6fe0f3c6b5814dd2f49030e7ed))
### 🐛 Bug Fixes
- Parsing mixed-case language codes like zh-CN - ([9c73ed4](https://codeberg.org/ThetaDev/rustypipe/commit/9c73ed4b3008cb093c0fa7fd94fd9f1ba8cd3627))
### 🚜 Refactor
- [**breaking**] Add client_type field to DownloadError, rename cli option po-token-cache to pot-cache - ([594e675](https://codeberg.org/ThetaDev/rustypipe/commit/594e675b39efc5fbcdbd5e920a4d2cdee64f718e))
- Rename rustypipe-cli binary to rustypipe - ([c1a872e](https://codeberg.org/ThetaDev/rustypipe/commit/c1a872e1c14ea0956053bd7c65f6875b1cb3bc55))
### 📚 Documentation
- Add Botguard info to README - ([9957add](https://codeberg.org/ThetaDev/rustypipe/commit/9957add2b5d6391b2c1869d2019fd7dd91b8cd41))
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rustypipe to 0.10.0
- *(deps)* Update rust crate rquickjs to 0.9.0 (#33) - ([2c8ac41](https://codeberg.org/ThetaDev/rustypipe/commit/2c8ac410aa535d83f8bcc7181f81914b13bceb77))
## [v0.6.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-cli/v0.5.0..rustypipe-cli/v0.6.0) - 2025-01-16 ## [v0.6.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-cli/v0.5.0..rustypipe-cli/v0.6.0) - 2025-01-16
### 🚀 Features ### 🚀 Features

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rustypipe-cli" name = "rustypipe-cli"
version = "0.6.0" version = "0.7.2"
rust-version = "1.70.0" rust-version = "1.70.0"
edition.workspace = true edition.workspace = true
authors.workspace = true authors.workspace = true
@ -12,6 +12,7 @@ description = "CLI for RustyPipe - download videos and extract data from YouTube
[features] [features]
default = ["native-tls"] default = ["native-tls"]
timezone = ["dep:time", "dep:time-tz"]
# Reqwest TLS options # Reqwest TLS options
native-tls = [ native-tls = [
@ -41,7 +42,7 @@ rustls-tls-native-roots = [
] ]
[dependencies] [dependencies]
rustypipe = { workspace = true, features = ["rss"] } rustypipe = { workspace = true, features = ["rss", "userdata"] }
rustypipe-downloader.workspace = true rustypipe-downloader.workspace = true
reqwest.workspace = true reqwest.workspace = true
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
@ -49,6 +50,8 @@ futures-util.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
quick-xml.workspace = true quick-xml.workspace = true
time = { workspace = true, optional = true }
time-tz = { version = "2.0.0", optional = true }
indicatif.workspace = true indicatif.workspace = true
anyhow.workspace = true anyhow.workspace = true
@ -61,3 +64,7 @@ dirs.workspace = true
anstream = "0.6.15" anstream = "0.6.15"
owo-colors = "4.0.0" owo-colors = "4.0.0"
const_format = "0.2.33" const_format = "0.2.33"
[[bin]]
name = "rustypipe"
path = "src/main.rs"

View file

@ -8,7 +8,19 @@ The RustyPipe CLI is a powerful YouTube client for the command line. It allows y
access most of the features of the RustyPipe crate: getting data from YouTube and access most of the features of the RustyPipe crate: getting data from YouTube and
downloading videos. downloading videos.
The following subcommands are included: ## Installation
You can download a compiled version of RustyPipe here:
<https://codeberg.org/ThetaDev/rustypipe/releases>
Alternatively, you can compile it yourself by installing [Rust](https://rustup.rs/) and
running `cargo install rustypipe-cli`.
To be able to access streams from web-based clients (Desktop, Mobile) you need to
download [rustypipe-botguard](https://codeberg.org/ThetaDev/rustypipe-botguard/releases)
and place the binary either in the PATH or the current working directory.
For downloading videos you also need to have ffmpeg installed.
## `get`: Fetch information ## `get`: Fetch information
@ -127,14 +139,21 @@ Fetch a list of all the items saved in your YouTube/YouTube Music profile.
- **Proxy:** RustyPipe respects the environment variables `HTTP_PROXY`, `HTTPS_PROXY` - **Proxy:** RustyPipe respects the environment variables `HTTP_PROXY`, `HTTPS_PROXY`
and `ALL_PROXY` and `ALL_PROXY`
- **Logging:** You can change the log level with the `RUST_LOG` environment variable, it - **Logging:** Enable debug logging with the `-v` (verbose) flag. If you want more
is set to `info` by default fine-grained control, use the `RUST_LOG` environment variable.
- **Visitor data:** A custom visitor data ID can be used with the `--vdata` flag - **Visitor data:** A custom visitor data ID can be used with the `--vdata` flag
- **Authentication:** Use the commands `rustypipe login` and `rustypipe login --cookie` - **Authentication:** Use the commands `rustypipe login` and `rustypipe login --cookie`
to log into your Google account using either OAuth or YouTube cookies. With the to log into your Google account using either OAuth or YouTube cookies. With the
`--auth` flag you can use authentication for any request. `--auth` flag you can use authentication for any request.
- `--lang` Change the YouTube content language - `--lang` Change the YouTube content language
- `--country` Change the YouTube content country - `--country` Change the YouTube content country
- `--tz` Use a specific
[timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g.
Europe/Berlin, Australia/Sydney)
**Note:** this requires building rustypipe-cli with the `timezone` feature
- `--local-tz` Use the local timezone instead of UTC
- `--report` Generate a report on every request and store it in a `rustypipe_reports` - `--report` Generate a report on every request and store it in a `rustypipe_reports`
folder in the current directory folder in the current directory
- `--cache-file` Change the RustyPipe cache file location (Default: - `--cache-file` Change the RustyPipe cache file location (Default:

View file

@ -55,6 +55,13 @@ struct Cli {
/// YouTube content country /// YouTube content country
#[clap(long, global = true)] #[clap(long, global = true)]
country: Option<String>, country: Option<String>,
/// Use a specific timezone (e.g. Europe/Berlin, Australia/Sydney)
#[cfg(feature = "timezone")]
#[clap(long, global = true)]
tz: Option<String>,
/// Use local timezone
#[clap(long, global = true)]
tz_local: bool,
/// Use authentication /// Use authentication
#[clap(long, global = true)] #[clap(long, global = true)]
auth: bool, auth: bool,
@ -73,6 +80,9 @@ struct Cli {
/// Enable caching for session-bound PO tokens /// Enable caching for session-bound PO tokens
#[clap(long, global = true)] #[clap(long, global = true)]
pot_cache: bool, pot_cache: bool,
/// Enable debug logging
#[clap(short, long, global = true)]
verbose: bool,
} }
#[derive(Parser)] #[derive(Parser)]
@ -871,12 +881,15 @@ async fn run() -> anyhow::Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
let multi = MultiProgress::new(); let multi = MultiProgress::new();
let mut env_filter = EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy();
if cli.verbose {
env_filter = env_filter.add_directive("rustypipe=debug".parse().unwrap());
}
tracing_subscriber::fmt::SubscriberBuilder::default() tracing_subscriber::fmt::SubscriberBuilder::default()
.with_env_filter( .with_env_filter(env_filter)
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.with_writer(ProgWriter(multi.clone())) .with_writer(ProgWriter(multi.clone()))
.init(); .init();
@ -913,6 +926,23 @@ async fn run() -> anyhow::Result<()> {
if let Some(botguard_bin) = cli.botguard_bin { if let Some(botguard_bin) = cli.botguard_bin {
rp = rp.botguard_bin(botguard_bin); rp = rp.botguard_bin(botguard_bin);
} }
if cli.tz_local {
rp = rp.timezone_local();
}
#[cfg(feature = "timezone")]
if let Some(timezone) = cli.tz {
use time::OffsetDateTime;
use time_tz::{Offset, TimeZone};
let tz = time_tz::timezones::get_by_name(&timezone).expect("invalid timezone");
let offset = tz
.get_offset_utc(&OffsetDateTime::now_utc())
.to_utc()
.whole_minutes();
rp = rp.timezone(tz.name(), offset);
}
if cli.no_botguard { if cli.no_botguard {
rp = rp.no_botguard(); rp = rp.no_botguard();
} }

View file

@ -9,7 +9,7 @@ repository.workspace = true
publish = false publish = false
[dependencies] [dependencies]
rustypipe = { path = "../" } rustypipe = { path = "../", features = ["userdata"] }
reqwest.workspace = true reqwest.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread"] } tokio = { workspace = true, features = ["rt-multi-thread"] }
futures-util.workspace = true futures-util.workspace = true

View file

@ -40,12 +40,15 @@ pub enum ABTest {
MusicPlaylistFacepile = 18, MusicPlaylistFacepile = 18,
MusicAlbumGroupsReordered = 19, MusicAlbumGroupsReordered = 19,
MusicContinuationItemRenderer = 20, MusicContinuationItemRenderer = 20,
AlbumRecommends = 21,
CommandExecutorCommand = 22,
} }
/// List of active A/B tests that are run when none is manually specified /// List of active A/B tests that are run when none is manually specified
const TESTS_TO_RUN: &[ABTest] = &[ const TESTS_TO_RUN: &[ABTest] = &[
ABTest::MusicAlbumGroupsReordered, ABTest::MusicAlbumGroupsReordered,
ABTest::MusicContinuationItemRenderer, ABTest::AlbumRecommends,
ABTest::CommandExecutorCommand,
]; ];
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -121,6 +124,8 @@ pub async fn run_test(
ABTest::MusicContinuationItemRenderer => { ABTest::MusicContinuationItemRenderer => {
music_continuation_item_renderer(&query).await music_continuation_item_renderer(&query).await
} }
ABTest::AlbumRecommends => album_recommends(&query).await,
ABTest::CommandExecutorCommand => command_executor_command(&query).await,
} }
.unwrap(); .unwrap();
pb.inc(1); pb.inc(1);
@ -443,3 +448,33 @@ pub async fn music_continuation_item_renderer(rp: &RustyPipeQuery) -> Result<boo
.await?; .await?;
Ok(res.contains("\"continuationItemRenderer\"")) Ok(res.contains("\"continuationItemRenderer\""))
} }
pub async fn album_recommends(rp: &RustyPipeQuery) -> Result<bool> {
let id = "MPREb_u1I69lSAe5v";
let res = rp
.raw(
ClientType::DesktopMusic,
"browse",
&QBrowse {
browse_id: id,
params: None,
},
)
.await?;
Ok(res.contains("\"musicCarouselShelfRenderer\""))
}
pub async fn command_executor_command(rp: &RustyPipeQuery) -> Result<bool> {
let id = "VLPLbZIPy20-1pN7mqjckepWF78ndb6ci_qi";
let res = rp
.raw(
ClientType::Desktop,
"browse",
&QBrowse {
browse_id: id,
params: None,
},
)
.await?;
Ok(res.contains("\"commandExecutorCommand\""))
}

View file

@ -0,0 +1,130 @@
use std::{collections::BTreeMap, fs::File, io::BufReader};
use path_macro::path;
use rustypipe::{
client::{ClientType, RustyPipe},
param::{Language, LANGUAGES},
};
use serde::Deserialize;
use serde_with::rust::deserialize_ignore_any;
use crate::{
model::{QBrowse, SectionList, TextRuns},
util::{self, DICT_DIR},
};
pub async fn collect_album_versions_titles() {
let json_path = path!(*DICT_DIR / "other_versions_titles.json");
let mut res = BTreeMap::new();
let rp = RustyPipe::new();
for lang in LANGUAGES {
let query = QBrowse {
browse_id: "MPREb_nlBWQROfvjo",
params: None,
};
let raw_resp = rp
.query()
.lang(lang)
.raw(ClientType::DesktopMusic, "browse", &query)
.await
.unwrap();
let data = serde_json::from_str::<AlbumData>(&raw_resp).unwrap();
let title = data
.contents
.two_column_browse_results_renderer
.secondary_contents
.section_list_renderer
.contents
.into_iter()
.find_map(|x| match x {
ItemSection::MusicCarouselShelfRenderer(music_carousel_shelf) => {
Some(music_carousel_shelf)
}
ItemSection::None => None,
})
.expect("other versions")
.header
.expect("header")
.music_carousel_shelf_basic_header_renderer
.title
.runs
.into_iter()
.next()
.unwrap()
.text;
println!("{lang}: {title}");
res.insert(lang, title);
}
let file = File::create(json_path).unwrap();
serde_json::to_writer_pretty(file, &res).unwrap();
}
pub fn write_samples_to_dict() {
let json_path = path!(*DICT_DIR / "other_versions_titles.json");
let json_file = File::open(json_path).unwrap();
let collected: BTreeMap<Language, String> =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
let mut dict = util::read_dict();
let langs = dict.keys().copied().collect::<Vec<_>>();
for lang in langs {
let dict_entry = dict.entry(lang).or_default();
let e = collected.get(&lang).unwrap();
assert_eq!(e, e.trim());
dict_entry.album_versions_title = e.to_owned();
for lang in &dict_entry.equivalent {
let ee = collected.get(lang).unwrap();
if ee != e {
panic!("equivalent lang conflict, lang: {lang}");
}
}
}
util::write_dict(dict);
}
#[derive(Debug, Deserialize)]
struct AlbumData {
contents: AlbumDataContents,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct AlbumDataContents {
two_column_browse_results_renderer: X1,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct X1 {
secondary_contents: SectionList<ItemSection>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
enum ItemSection {
MusicCarouselShelfRenderer(MusicCarouselShelf),
#[serde(other, deserialize_with = "deserialize_ignore_any")]
None,
}
#[derive(Debug, Deserialize)]
struct MusicCarouselShelf {
header: Option<MusicCarouselShelfHeader>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct MusicCarouselShelfHeader {
music_carousel_shelf_basic_header_renderer: MusicCarouselShelfHeaderRenderer,
}
#[derive(Debug, Deserialize)]
struct MusicCarouselShelfHeaderRenderer {
title: TextRuns,
}

View file

@ -204,8 +204,6 @@ pub fn parse_video_durations() {
parse(&mut words, lang, dict_entry.by_char, txt, *d); parse(&mut words, lang, dict_entry.by_char, txt, *d);
} }
// dbg!(&words);
for (k, v) in words { for (k, v) in words {
if let Some(v) = v { if let Some(v) = v {
dict_entry.timeago_tokens.insert(k, v.to_string()); dict_entry.timeago_tokens.insert(k, v.to_string());

View file

@ -39,9 +39,6 @@ pub async fn download_testfiles() {
search_playlists().await; search_playlists().await;
search_empty().await; search_empty().await;
trending().await; trending().await;
history().await;
subscriptions().await;
subscription_feed().await;
music_playlist().await; music_playlist().await;
music_playlist_cont().await; music_playlist_cont().await;
@ -65,6 +62,12 @@ pub async fn download_testfiles() {
music_charts().await; music_charts().await;
music_genres().await; music_genres().await;
music_genre().await; music_genre().await;
// User data
history().await;
subscriptions().await;
subscription_feed().await;
music_history().await; music_history().await;
music_saved_artists().await; music_saved_artists().await;
music_saved_albums().await; music_saved_albums().await;
@ -464,7 +467,7 @@ async fn trending() {
} }
async fn history() { async fn history() {
let json_path = path!(*TESTFILES_DIR / "history" / "history.json"); let json_path = path!(*TESTFILES_DIR / "userdata" / "history.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -474,7 +477,7 @@ async fn history() {
} }
async fn subscriptions() { async fn subscriptions() {
let json_path = path!(*TESTFILES_DIR / "history" / "subscriptions.json"); let json_path = path!(*TESTFILES_DIR / "userdata" / "subscriptions.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -484,7 +487,7 @@ async fn subscriptions() {
} }
async fn subscription_feed() { async fn subscription_feed() {
let json_path = path!(*TESTFILES_DIR / "history" / "subscription_feed.json"); let json_path = path!(*TESTFILES_DIR / "userdata" / "subscription_feed.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -816,7 +819,7 @@ async fn music_genre() {
} }
async fn music_history() { async fn music_history() {
let json_path = path!(*TESTFILES_DIR / "music_history" / "music_history.json"); let json_path = path!(*TESTFILES_DIR / "music_userdata" / "music_history.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -826,7 +829,7 @@ async fn music_history() {
} }
async fn music_saved_artists() { async fn music_saved_artists() {
let json_path = path!(*TESTFILES_DIR / "music_history" / "saved_artists.json"); let json_path = path!(*TESTFILES_DIR / "music_userdata" / "saved_artists.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -836,7 +839,7 @@ async fn music_saved_artists() {
} }
async fn music_saved_albums() { async fn music_saved_albums() {
let json_path = path!(*TESTFILES_DIR / "music_history" / "saved_albums.json"); let json_path = path!(*TESTFILES_DIR / "music_userdata" / "saved_albums.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -846,7 +849,7 @@ async fn music_saved_albums() {
} }
async fn music_saved_tracks() { async fn music_saved_tracks() {
let json_path = path!(*TESTFILES_DIR / "music_history" / "saved_tracks.json"); let json_path = path!(*TESTFILES_DIR / "music_userdata" / "saved_tracks.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }
@ -856,7 +859,7 @@ async fn music_saved_tracks() {
} }
async fn music_saved_playlists() { async fn music_saved_playlists() {
let json_path = path!(*TESTFILES_DIR / "music_history" / "saved_playlists.json"); let json_path = path!(*TESTFILES_DIR / "music_userdata" / "saved_playlists.json");
if json_path.exists() { if json_path.exists() {
return; return;
} }

View file

@ -90,6 +90,8 @@ pub(crate) struct Entry {
pub chan_prefix: &'static str, pub chan_prefix: &'static str,
/// Channel name suffix on playlist pages /// Channel name suffix on playlist pages
pub chan_suffix: &'static str, pub chan_suffix: &'static str,
/// "Other versions" title on album pages
pub album_versions_title: &'static str,
} }
"#; "#;
@ -178,8 +180,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
.to_string() .to_string()
.replace('\n', "\n "); .replace('\n', "\n ");
write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n month_before_day: {:?},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n chan_prefix: {:?},\n chan_suffix: {:?},\n }},\n ", write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n month_before_day: {:?},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n chan_prefix: {:?},\n chan_suffix: {:?},\n album_versions_title: {:?},\n }},\n ",
selector, code_ta_tokens, entry.month_before_day, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types, entry.chan_prefix, entry.chan_suffix).unwrap(); selector, code_ta_tokens, entry.month_before_day, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types, entry.chan_prefix, entry.chan_suffix, entry.album_versions_title).unwrap();
} }
code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n"; code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n";

View file

@ -2,6 +2,7 @@
mod abtest; mod abtest;
mod collect_album_types; mod collect_album_types;
mod collect_album_versions_titles;
mod collect_chan_prefixes; mod collect_chan_prefixes;
mod collect_history_dates; mod collect_history_dates;
mod collect_large_numbers; mod collect_large_numbers;
@ -34,12 +35,14 @@ enum Commands {
CollectHistoryDates, CollectHistoryDates,
CollectMusicHistoryDates, CollectMusicHistoryDates,
CollectChanPrefixes, CollectChanPrefixes,
CollectAlbumVersionsTitles,
ParsePlaylistDates, ParsePlaylistDates,
ParseHistoryDates, ParseHistoryDates,
ParseLargeNumbers, ParseLargeNumbers,
ParseAlbumTypes, ParseAlbumTypes,
ParseVideoDurations, ParseVideoDurations,
ParseChanPrefixes, ParseChanPrefixes,
ParseAlbumVersionsTitles,
GenLocales, GenLocales,
GenDict, GenDict,
DownloadTestfiles, DownloadTestfiles,
@ -58,28 +61,25 @@ async fn main() {
match cli.command { match cli.command {
Commands::CollectPlaylistDates => { Commands::CollectPlaylistDates => {
collect_playlist_dates::collect_dates(cli.concurrency).await; collect_playlist_dates::collect_dates(cli.concurrency).await
} }
Commands::CollectLargeNumbers => { Commands::CollectLargeNumbers => {
collect_large_numbers::collect_large_numbers(cli.concurrency).await; collect_large_numbers::collect_large_numbers(cli.concurrency).await
} }
Commands::CollectAlbumTypes => { Commands::CollectAlbumTypes => {
collect_album_types::collect_album_types(cli.concurrency).await; collect_album_types::collect_album_types(cli.concurrency).await
} }
Commands::CollectVideoDurations => { Commands::CollectVideoDurations => {
collect_video_durations::collect_video_durations(cli.concurrency).await; collect_video_durations::collect_video_durations(cli.concurrency).await
} }
Commands::CollectVideoDates => { Commands::CollectVideoDates => {
collect_video_dates::collect_video_dates(cli.concurrency).await; collect_video_dates::collect_video_dates(cli.concurrency).await
} }
Commands::CollectHistoryDates => { Commands::CollectHistoryDates => collect_history_dates::collect_dates().await,
collect_history_dates::collect_dates().await; Commands::CollectMusicHistoryDates => collect_history_dates::collect_dates_music().await,
} Commands::CollectChanPrefixes => collect_chan_prefixes::collect_chan_prefixes().await,
Commands::CollectMusicHistoryDates => { Commands::CollectAlbumVersionsTitles => {
collect_history_dates::collect_dates_music().await; collect_album_versions_titles::collect_album_versions_titles().await
}
Commands::CollectChanPrefixes => {
collect_chan_prefixes::collect_chan_prefixes().await;
} }
Commands::ParsePlaylistDates => collect_playlist_dates::write_samples_to_dict(), Commands::ParsePlaylistDates => collect_playlist_dates::write_samples_to_dict(),
Commands::ParseHistoryDates => collect_history_dates::write_samples_to_dict(), Commands::ParseHistoryDates => collect_history_dates::write_samples_to_dict(),
@ -87,9 +87,10 @@ async fn main() {
Commands::ParseAlbumTypes => collect_album_types::write_samples_to_dict(), Commands::ParseAlbumTypes => collect_album_types::write_samples_to_dict(),
Commands::ParseVideoDurations => collect_video_durations::parse_video_durations(), Commands::ParseVideoDurations => collect_video_durations::parse_video_durations(),
Commands::ParseChanPrefixes => collect_chan_prefixes::write_samples_to_dict(), Commands::ParseChanPrefixes => collect_chan_prefixes::write_samples_to_dict(),
Commands::GenLocales => { Commands::ParseAlbumVersionsTitles => {
gen_locales::generate_locales().await; collect_album_versions_titles::write_samples_to_dict()
} }
Commands::GenLocales => gen_locales::generate_locales().await,
Commands::GenDict => gen_dictionary::generate_dictionary(), Commands::GenDict => gen_dictionary::generate_dictionary(),
Commands::DownloadTestfiles => download_testfiles::download_testfiles().await, Commands::DownloadTestfiles => download_testfiles::download_testfiles().await,
Commands::AbTest { id, n } => { Commands::AbTest { id, n } => {

View file

@ -61,6 +61,8 @@ pub struct DictEntry {
pub chan_prefix: String, pub chan_prefix: String,
/// Channel name suffix on playlist pages /// Channel name suffix on playlist pages
pub chan_suffix: String, pub chan_suffix: String,
/// "Other versions" title on album pages
pub album_versions_title: String,
} }
/// Parsed TimeAgo string, contains amount and time unit. /// Parsed TimeAgo string, contains amount and time unit.

View file

@ -3,6 +3,37 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [v0.3.1](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-downloader/v0.3.0..rustypipe-downloader/v0.3.1) - 2024-12-20
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rustypipe to 0.11.0
## [v0.3.0](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-downloader/v0.2.7..rustypipe-downloader/v0.3.0) - 2025-02-09
### 🚀 Features
- [**breaking**] Remove manual PO token options from downloader in favor of rustypipe-botguard - ([cddb32f](https://codeberg.org/ThetaDev/rustypipe/commit/cddb32f190276265258c6ab45b3d43a8891c4b39))
### 🐛 Bug Fixes
- Ensure downloader futures are send - ([812ff4c](https://codeberg.org/ThetaDev/rustypipe/commit/812ff4c5bafffc5708a6d5066f1ebadb6d9fc958))
- Download audio with dolby codec - ([9234005](https://codeberg.org/ThetaDev/rustypipe/commit/92340056f868007beccb64e9e26eb39abc40f7aa))
### 🚜 Refactor
- [**breaking**] Add client_type field to DownloadError, rename cli option po-token-cache to pot-cache - ([594e675](https://codeberg.org/ThetaDev/rustypipe/commit/594e675b39efc5fbcdbd5e920a4d2cdee64f718e))
### 📚 Documentation
- Add Botguard info to README - ([9957add](https://codeberg.org/ThetaDev/rustypipe/commit/9957add2b5d6391b2c1869d2019fd7dd91b8cd41))
### ⚙️ Miscellaneous Tasks
- *(deps)* Update rustypipe to 0.10.0
## [v0.2.7](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-downloader/v0.2.6..rustypipe-downloader/v0.2.7) - 2025-01-16 ## [v0.2.7](https://codeberg.org/ThetaDev/rustypipe/compare/rustypipe-downloader/v0.2.6..rustypipe-downloader/v0.2.7) - 2025-01-16
### 🚀 Features ### 🚀 Features

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rustypipe-downloader" name = "rustypipe-downloader"
version = "0.2.7" version = "0.3.1"
rust-version = "1.67.1" rust-version = "1.67.1"
edition.workspace = true edition.workspace = true
authors.workspace = true authors.workspace = true
@ -51,7 +51,7 @@ image = { version = "0.25.0", optional = true, default-features = false, feature
"jpeg", "jpeg",
"webp", "webp",
] } ] }
smartcrop2 = { version = "0.3.1", optional = true } smartcrop2 = { version = "0.4.0", optional = true }
[dev-dependencies] [dev-dependencies]
path_macro.workspace = true path_macro.workspace = true

View file

@ -1033,9 +1033,13 @@ impl DownloadQuery {
image::load_from_memory(&img_bts)? image::load_from_memory(&img_bts)?
}; };
let crop = smartcrop::find_best_crop(&img, NonZeroU32::MIN, NonZeroU32::MIN) let crop = smartcrop::find_best_crop_no_borders(
.map_err(|e| DownloadError::AudioTag(format!("image crop: {e}").into()))? &img,
.crop; NonZeroU32::MIN,
NonZeroU32::MIN,
)
.map_err(|e| DownloadError::AudioTag(format!("image crop: {e}").into()))?
.crop;
img = img.crop_imm(crop.x, crop.y, crop.width, crop.height); img = img.crop_imm(crop.x, crop.y, crop.width, crop.height);
let mut enc_bts = Vec::new(); let mut enc_bts = Vec::new();
img.write_with_encoder(image::codecs::jpeg::JpegEncoder::new_with_quality( img.write_with_encoder(image::codecs::jpeg::JpegEncoder::new_with_quality(
@ -1063,8 +1067,8 @@ impl DownloadQuery {
} }
fn get_download_range(offset: u64, size: Option<u64>) -> Range<u64> { fn get_download_range(offset: u64, size: Option<u64>) -> Range<u64> {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let chunk_size = rng.gen_range(CHUNK_SIZE_MIN..CHUNK_SIZE_MAX); let chunk_size = rng.random_range(CHUNK_SIZE_MIN..CHUNK_SIZE_MAX);
let mut chunk_end = offset + chunk_size; let mut chunk_end = offset + chunk_size;
if let Some(size) = size { if let Some(size) = size {
@ -1197,6 +1201,8 @@ async fn download_single_file(
} }
} }
tracing::debug!("downloading {} to {}", url, output.to_string_lossy());
let mut file = fs::OpenOptions::new() let mut file = fs::OpenOptions::new()
.append(true) .append(true)
.create(true) .create(true)

View file

@ -3,13 +3,13 @@
When YouTube introduces a new feature, it does so gradually. When a user creates a new When YouTube introduces a new feature, it does so gradually. When a user creates a new
session, YouTube decided randomly which new features should be enabled. session, YouTube decided randomly which new features should be enabled.
YouTube sessions are identified by the visitor data ID. This cookie is sent with YouTube sessions are identified by the visitor data ID. This cookie is sent with every
every API request using the `context.client.visitor_data` JSON parameter. It is also API request using the `context.client.visitor_data` JSON parameter. It is also returned
returned in the `responseContext.visitorData` response parameter and stored as the in the `responseContext.visitorData` response parameter and stored as the `__SECURE-YEC`
`__SECURE-YEC` cookie. cookie.
By sending the same visitor data ID, A/B tests can be reproduced, which is important By sending the same visitor data ID, A/B tests can be reproduced, which is important for
for testing alternative YouTube clients. testing alternative YouTube clients.
This page lists all A/B tests that were encountered while maintaining the RustyPipe This page lists all A/B tests that were encountered while maintaining the RustyPipe
client. client.
@ -1030,7 +1030,7 @@ commandContext missing).
- **Encountered on:** 13.01.2025 - **Encountered on:** 13.01.2025
- **Impact:** 🟢 Low - **Impact:** 🟢 Low
- **Endpoint:** browse (YTM) - **Endpoint:** browse (YTM)
- **Status:** Common (10%) - **Status:** Frequent (59%)
YouTube Music used to group artist albums into 2 rows: "Albums" and "Singles". YouTube Music used to group artist albums into 2 rows: "Albums" and "Singles".
@ -1042,7 +1042,7 @@ omitted for albums in their group, while singles and EPs have a label with their
- **Encountered on:** 25.01.2025 - **Encountered on:** 25.01.2025
- **Impact:** 🟢 Low - **Impact:** 🟢 Low
- **Endpoint:** browse (YTM) - **Endpoint:** browse (YTM)
- **Status:** Common (4%) - **Status:** Stabilized
YouTube Music now uses a `continuationItemRenderer` for music playlists instead of YouTube Music now uses a `continuationItemRenderer` for music playlists instead of
putting the continuations in a separate attribute of the MusicShelf. putting the continuations in a separate attribute of the MusicShelf.
@ -1052,3 +1052,52 @@ items.
YouTube Music now also sends a random 16-character string as a `clientScreenNonce` in YouTube Music now also sends a random 16-character string as a `clientScreenNonce` in
the request context. This is not mandatory though. the request context. This is not mandatory though.
## [21] Music album recommendations
- **Encountered on:** 26.02.2025
- **Impact:** 🟢 Low
- **Endpoint:** browse (YTM)
- **Status:** Common (15%)
![A/B test 21 screenshot](./_img/ab_21.png)
YouTube Music has added "Recommended" and "More from \<Artist\>" carousels to album
pages. The difficulty is distinguishing them reliably for parsing the album variants.
The current solution is adding the "Other versions" title in all languages to the
dictionary and comparing it.
## [22] commandExecutorCommand for continuations
- **Encountered on:** 16.03.2025
- **Impact:** 🟢 Low
- **Endpoint:** browse (YTM)
- **Status:** Experimental (1%)
YouTube playlists may use a commandExecutorCommand which holds a list of commands: the
`continuationCommand` that needs to be extracted as well as a `playlistVotingRefreshPopupCommand`.
```json
{
"continuationItemRenderer": {
"continuationEndpoint": {
"commandExecutorCommand": {
"commands": [
{
"playlistVotingRefreshPopupCommand": {
"command": {}
}
},
{
"continuationCommand": {
"request": "CONTINUATION_REQUEST_TYPE_BROWSE",
"token": "4qmFsgKBARIkVkxQTGJaSVB5MjAtMXBON21xamNrZXBXRjc4bmRiNmNpX3FpGjRDQUY2SGxCVU9rTklTV2xGUkVreVVtdEZOVTVFU1hsU2FrWkRVa1JKZWs1NldRJTNEJTNEmgIiUExiWklQeTIwLTFwTjdtcWpja2VwV0Y3OG5kYjZjaV9xaQ%3D%3D"
}
}
]
}
}
}
}
```

BIN
notes/_img/ab_21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

View file

@ -280,7 +280,7 @@ impl MapResponse<Channel<Paginator<PlaylistItem>>> for response::Channel {
impl MapResponse<ChannelInfo> for response::ChannelAbout { impl MapResponse<ChannelInfo> for response::ChannelAbout {
fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<ChannelInfo>, ExtractionError> { fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<ChannelInfo>, ExtractionError> {
// Channel info is always fetched in English. There is no localized data there // Channel info is always fetched in English. There is no localized data
// and it allows parsing the country name. // and it allows parsing the country name.
let lang = Language::En; let lang = Language::En;
@ -335,7 +335,7 @@ impl MapResponse<ChannelInfo> for response::ChannelAbout {
.video_count_text .video_count_text
.and_then(|txt| util::parse_numeric_or_warn(&txt, &mut warnings)), .and_then(|txt| util::parse_numeric_or_warn(&txt, &mut warnings)),
create_date: about.joined_date_text.and_then(|txt| { create_date: about.joined_date_text.and_then(|txt| {
timeago::parse_textual_date_or_warn(lang, &txt, &mut warnings) timeago::parse_textual_date_or_warn(lang, ctx.utc_offset, &txt, &mut warnings)
.map(OffsetDateTime::date) .map(OffsetDateTime::date)
}), }),
view_count: about view_count: about
@ -468,8 +468,9 @@ fn map_channel(
let subscriber_count = sub_part.and_then(|t| { let subscriber_count = sub_part.and_then(|t| {
util::parse_large_numstr_or_warn::<u64>(t.as_str(), ctx.lang, &mut warnings) util::parse_large_numstr_or_warn::<u64>(t.as_str(), ctx.lang, &mut warnings)
}); });
let video_count = let video_count = vc_part.and_then(|t| {
vc_part.and_then(|t| util::parse_numeric_or_warn(t.as_str(), &mut warnings)); util::parse_large_numstr_or_warn(t.as_str(), ctx.lang, &mut warnings)
});
Channel { Channel {
id: metadata.external_id, id: metadata.external_id,

View file

@ -3,7 +3,7 @@ use std::fmt::Debug;
use crate::{ use crate::{
error::{Error, ExtractionError}, error::{Error, ExtractionError},
model::ChannelRss, model::ChannelRss,
report::{Report, RustyPipeInfo}, report::Report,
util, util,
}; };
@ -45,7 +45,7 @@ impl RustyPipeQuery {
Err(e) => { Err(e) => {
if let Some(reporter) = &self.client.inner.reporter { if let Some(reporter) = &self.client.inner.reporter {
let report = Report { let report = Report {
info: RustyPipeInfo::new(Some(self.opts.lang)), info: self.rp_info(),
level: crate::report::Level::ERR, level: crate::report::Level::ERR,
operation: "channel_rss", operation: "channel_rss",
error: Some(e.to_string()), error: Some(e.to_string()),

View file

@ -3,12 +3,10 @@
pub(crate) mod response; pub(crate) mod response;
mod channel; mod channel;
mod history;
mod music_artist; mod music_artist;
mod music_charts; mod music_charts;
mod music_details; mod music_details;
mod music_genres; mod music_genres;
mod music_history;
mod music_new; mod music_new;
mod music_playlist; mod music_playlist;
mod music_search; mod music_search;
@ -20,6 +18,13 @@ mod trends;
mod url_resolver; mod url_resolver;
mod video_details; mod video_details;
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
mod music_userdata;
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
mod userdata;
#[cfg(feature = "rss")] #[cfg(feature = "rss")]
#[cfg_attr(docsrs, doc(cfg(feature = "rss")))] #[cfg_attr(docsrs, doc(cfg(feature = "rss")))]
mod channel_rss; mod channel_rss;
@ -35,7 +40,7 @@ use regex::Regex;
use reqwest::{header, Client, ClientBuilder, Request, RequestBuilder, Response, StatusCode}; use reqwest::{header, Client, ClientBuilder, Request, RequestBuilder, Response, StatusCode};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use time::OffsetDateTime; use time::{OffsetDateTime, UtcOffset};
use tokio::sync::RwLock as AsyncRwLock; use tokio::sync::RwLock as AsyncRwLock;
use crate::error::AuthError; use crate::error::AuthError;
@ -83,7 +88,6 @@ pub enum ClientType {
/// Client used by the iOS app /// Client used by the iOS app
/// ///
/// - no obfuscated stream URLs /// - no obfuscated stream URLs
/// - does not include opus audio streams
Ios, Ios,
} }
@ -289,8 +293,10 @@ struct OauthToken {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
struct AuthCookie { struct AuthCookie {
cookie: String, cookie: String,
#[serde(alias = "account_syncid", skip_serializing_if = "Option::is_none")]
channel_syncid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
account_syncid: Option<String>, user_syncid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
session_index: Option<String>, session_index: Option<String>,
} }
@ -315,8 +321,9 @@ impl AuthCookie {
fn new(cookie: String) -> Self { fn new(cookie: String) -> Self {
Self { Self {
cookie, cookie,
account_syncid: None, channel_syncid: None,
session_index: None, session_index: None,
user_syncid: None,
} }
} }
} }
@ -358,6 +365,8 @@ const OAUTH_CLIENT_ID: &str =
const OAUTH_CLIENT_SECRET: &str = "SboVhoG9s0rNafixCSGGKXAT"; const OAUTH_CLIENT_SECRET: &str = "SboVhoG9s0rNafixCSGGKXAT";
const OAUTH_SCOPES: &str = "http://gdata.youtube.com https://www.googleapis.com/auth/youtube"; const OAUTH_SCOPES: &str = "http://gdata.youtube.com https://www.googleapis.com/auth/youtube";
const BOTGUARD_API_VERSION: &str = "1";
static CLIENT_VERSION_REGEX: Lazy<Regex> = static CLIENT_VERSION_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r#""INNERTUBE_CONTEXT_CLIENT_VERSION":"([\w\d\._-]+?)""#).unwrap()); Lazy::new(|| Regex::new(r#""INNERTUBE_CONTEXT_CLIENT_VERSION":"([\w\d\._-]+?)""#).unwrap());
@ -375,7 +384,7 @@ struct RustyPipeRef {
http: Client, http: Client,
storage: Option<Box<dyn CacheStorage>>, storage: Option<Box<dyn CacheStorage>>,
reporter: Option<Box<dyn Reporter>>, reporter: Option<Box<dyn Reporter>>,
n_request_attempts: u32, n_http_retries: u32,
cache: CacheHolder, cache: CacheHolder,
default_opts: RustyPipeOpts, default_opts: RustyPipeOpts,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
@ -387,6 +396,8 @@ struct RustyPipeRef {
struct RustyPipeOpts { struct RustyPipeOpts {
lang: Language, lang: Language,
country: Country, country: Country,
timezone: Option<String>,
utc_offset_minutes: i16,
report: bool, report: bool,
strict: bool, strict: bool,
auth: Option<bool>, auth: Option<bool>,
@ -397,17 +408,19 @@ struct RustyPipeOpts {
pub struct RustyPipeBuilder { pub struct RustyPipeBuilder {
storage: DefaultOpt<Box<dyn CacheStorage>>, storage: DefaultOpt<Box<dyn CacheStorage>>,
reporter: DefaultOpt<Box<dyn Reporter>>, reporter: DefaultOpt<Box<dyn Reporter>>,
n_request_attempts: u32, n_http_retries: u32,
timeout: DefaultOpt<Duration>, timeout: DefaultOpt<Duration>,
user_agent: Option<String>, user_agent: Option<String>,
default_opts: RustyPipeOpts, default_opts: RustyPipeOpts,
storage_dir: Option<PathBuf>, storage_dir: Option<PathBuf>,
botguard_bin: DefaultOpt<OsString>, botguard_bin: DefaultOpt<OsString>,
snapshot_file: Option<PathBuf>,
po_token_cache: bool, po_token_cache: bool,
} }
struct BotguardCfg { struct BotguardCfg {
program: OsString, program: OsString,
version: String,
snapshot_file: PathBuf, snapshot_file: PathBuf,
po_token_cache: bool, po_token_cache: bool,
} }
@ -435,13 +448,6 @@ impl<T> DefaultOpt<T> {
DefaultOpt::Default => Some(f()), DefaultOpt::Default => Some(f()),
} }
} }
fn or_default_opt<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
match self {
DefaultOpt::Some(x) => Some(x),
DefaultOpt::None => None,
DefaultOpt::Default => f(),
}
}
} }
/// # RustyPipe query /// # RustyPipe query
@ -502,6 +508,26 @@ impl<T> DefaultOpt<T> {
/// - [`music_new_albums`](RustyPipeQuery::music_new_albums) /// - [`music_new_albums`](RustyPipeQuery::music_new_albums)
/// - [`music_new_videos`](RustyPipeQuery::music_new_videos) /// - [`music_new_videos`](RustyPipeQuery::music_new_videos)
/// ///
/// ### User data (🔒 Feature `userdata`)
///
/// - **Playback history**
/// - [`history`](RustyPipeQuery::history)
/// - [`history_search`](RustyPipeQuery::history_search)
/// - [`music_history`](RustyPipeQuery::music_history)
/// - **YouTube library**
/// - [`liked_videos`](RustyPipeQuery::liked_videos)
/// - [`watch_later`](RustyPipeQuery::watch_later)
/// - [`saved_playlists`](RustyPipeQuery::saved_playlists)
/// - **Music library**
/// - [`music_saved_artists`](RustyPipeQuery::music_saved_artists)
/// - [`music_saved_albums`](RustyPipeQuery::music_saved_albums)
/// - [`music_saved_tracks`](RustyPipeQuery::music_saved_tracks)
/// - [`music_saved_playlists`](RustyPipeQuery::music_saved_playlists)
/// - [`music_liked_tracks`](RustyPipeQuery::music_liked_tracks)
/// - **Subscriptions**
/// - [`subscriptions`](RustyPipeQuery::subscriptions)
/// - [`subscription_feed`](RustyPipeQuery::subscription_feed)
///
/// ## Options /// ## Options
/// ///
/// You can set the language, country and visitor data ID for individual requests. /// You can set the language, country and visitor data ID for individual requests.
@ -526,6 +552,8 @@ impl Default for RustyPipeOpts {
Self { Self {
lang: Language::En, lang: Language::En,
country: Country::Us, country: Country::Us,
timezone: None,
utc_offset_minutes: 0,
report: false, report: false,
strict: false, strict: false,
auth: None, auth: None,
@ -652,10 +680,11 @@ impl RustyPipeBuilder {
storage: DefaultOpt::Default, storage: DefaultOpt::Default,
reporter: DefaultOpt::Default, reporter: DefaultOpt::Default,
timeout: DefaultOpt::Default, timeout: DefaultOpt::Default,
n_request_attempts: 2, n_http_retries: 2,
user_agent: None, user_agent: None,
storage_dir: None, storage_dir: None,
botguard_bin: DefaultOpt::Default, botguard_bin: DefaultOpt::Default,
snapshot_file: None,
po_token_cache: false, po_token_cache: false,
} }
} }
@ -721,27 +750,31 @@ impl RustyPipeBuilder {
let visitor_data_cache = VisitorDataCache::new(http.clone(), 50, 20); let visitor_data_cache = VisitorDataCache::new(http.clone(), 50, 20);
let botguard_bin = self.botguard_bin.or_default_opt(|| { let botguard = match self.botguard_bin {
let n = OsString::from("rustypipe-botguard"); DefaultOpt::Some(botguard_bin) => Some(detect_botguard_bin(botguard_bin)?),
let out = std::process::Command::new(&n) DefaultOpt::None => None,
.arg("--version") DefaultOpt::Default => detect_botguard_bin("./rustypipe-botguard".into())
.output() .or_else(|_| detect_botguard_bin("rustypipe-botguard".into()))
.ok()?; .map_err(|e| tracing::debug!("could not detect rustypipe-botguard: {e}"))
if !out.status.success() { .ok(),
return None; }
.map(|(program, version)| {
tracing::debug!(
"rustypipe-botguard: using {} at {}",
version,
program.to_string_lossy()
);
BotguardCfg {
program: program.to_owned(),
version,
snapshot_file: self.snapshot_file.unwrap_or_else(|| {
let mut snapshot_file = storage_dir.clone();
snapshot_file.push("bg_snapshot.bin");
snapshot_file
}),
po_token_cache: self.po_token_cache,
} }
let output = String::from_utf8_lossy(&out.stdout);
let pat = "rustypipe-botguard-api ";
let pos = output.find(pat)? + pat.len();
let pos_end = output[pos..]
.char_indices()
.find(|(_, c)| !c.is_ascii_digit())
.map(|(p, _)| p + pos)
.unwrap_or(output.len());
if &output[pos..pos_end] != "1" {
return None;
}
Some(n)
}); });
Ok(RustyPipe { Ok(RustyPipe {
@ -749,11 +782,11 @@ impl RustyPipeBuilder {
http, http,
storage, storage,
reporter: self.reporter.or_default(|| { reporter: self.reporter.or_default(|| {
let mut report_dir = storage_dir.clone(); let mut report_dir = storage_dir;
report_dir.push(DEFAULT_REPORT_DIR); report_dir.push(DEFAULT_REPORT_DIR);
Box::new(FileReporter::new(report_dir)) Box::new(FileReporter::new(report_dir))
}), }),
n_request_attempts: self.n_request_attempts, n_http_retries: self.n_http_retries,
cache: CacheHolder { cache: CacheHolder {
clients: cache_clients, clients: cache_clients,
deobf: AsyncRwLock::new(cdata.deobf), deobf: AsyncRwLock::new(cdata.deobf),
@ -763,15 +796,7 @@ impl RustyPipeBuilder {
default_opts: self.default_opts, default_opts: self.default_opts,
user_agent, user_agent,
visitor_data_cache, visitor_data_cache,
botguard: botguard_bin.map(|program| { botguard,
let mut snapshot_file = storage_dir;
snapshot_file.push("bg_snapshot.bin");
BotguardCfg {
program,
snapshot_file,
po_token_cache: self.po_token_cache,
}
}),
}), }),
}) })
} }
@ -840,9 +865,9 @@ impl RustyPipeBuilder {
self self
} }
/// Set the maximum number of attempts for HTTP requests (at least 1). /// Set the maximum number of retries for YouTube requests.
/// ///
/// If a HTTP requests fails because of a serverside error and retries are enabled, /// If a request fails because of a serverside error and retries are enabled,
/// RustyPipe waits 1 second before the next attempt. /// RustyPipe waits 1 second before the next attempt.
/// ///
/// The wait time is doubled for subsequent attempts (including a bit of /// The wait time is doubled for subsequent attempts (including a bit of
@ -850,8 +875,8 @@ impl RustyPipeBuilder {
/// ///
/// **Default value**: 2 /// **Default value**: 2
#[must_use] #[must_use]
pub fn n_request_attempts(mut self, n_retries: u32) -> Self { pub fn n_http_retries(mut self, n_retries: u32) -> Self {
self.n_request_attempts = n_retries.max(1); self.n_http_retries = n_retries.max(1);
self self
} }
@ -891,6 +916,29 @@ impl RustyPipeBuilder {
self self
} }
/// Set the timezone and its associated UTC offset in minutes used
/// when accessing the YouTube API.
///
/// **Default value**: `0` (UTC)
///
/// **Info**: you can set this option for individual queries, too
#[must_use]
pub fn timezone<S: Into<String>>(mut self, timezone: S, utc_offset_minutes: i16) -> Self {
self.default_opts.timezone = Some(timezone.into());
self.default_opts.utc_offset_minutes = utc_offset_minutes;
self
}
/// Access the YouTube API using the local system timezone
///
/// If the local timezone could not be determined, an error is logged and RustyPipe falls
/// back to UTC.
#[must_use]
pub fn timezone_local(self) -> Self {
let (timezone, utc_offset_minutes) = local_tz_offset();
self.timezone(timezone, utc_offset_minutes)
}
/// Generate a report on every operation. /// Generate a report on every operation.
/// ///
/// This should only be used for debugging. /// This should only be used for debugging.
@ -984,6 +1032,18 @@ impl RustyPipeBuilder {
self self
} }
/// Set the path where the rustypipe-botguard snapshot file is stored
///
/// After solving a Botguard challenge, rustypipe-botguard stores its
/// JavaScript environment in a snapshot file, so it can quickly generate additional tokens.
///
/// By default the snapshot is stored in the storage_dir (Filename: bg_snapshot.bin).
#[must_use]
pub fn botguard_snapshot_file<P: Into<PathBuf>>(mut self, snapshot_file: P) -> Self {
self.snapshot_file = Some(snapshot_file.into());
self
}
/// Enable caching for session-bound PO tokens /// Enable caching for session-bound PO tokens
/// ///
/// By default, RustyPipe calls Botguard for every player request to fetch both a /// By default, RustyPipe calls Botguard for every player request to fetch both a
@ -1034,7 +1094,7 @@ impl RustyPipe {
/// Execute the given http request. /// Execute the given http request.
async fn http_request(&self, request: &Request) -> Result<Response, reqwest::Error> { async fn http_request(&self, request: &Request) -> Result<Response, reqwest::Error> {
let mut last_resp = None; let mut last_resp = None;
for n in 0..=self.inner.n_request_attempts { for n in 0..=self.inner.n_http_retries {
let resp = self.inner.http.execute(request.try_clone().unwrap()).await; let resp = self.inner.http.execute(request.try_clone().unwrap()).await;
let err = match resp { let err = match resp {
@ -1060,7 +1120,7 @@ impl RustyPipe {
}; };
// Retry in case of a recoverable status code (server err, too many requests) // Retry in case of a recoverable status code (server err, too many requests)
if n != self.inner.n_request_attempts { if n != self.inner.n_http_retries {
let ms = util::retry_delay(n, 1000, 60000, 3); let ms = util::retry_delay(n, 1000, 60000, 3);
tracing::warn!( tracing::warn!(
"Retry attempt #{}. Error: {}. Waiting {} ms", "Retry attempt #{}. Error: {}. Waiting {} ms",
@ -1534,6 +1594,17 @@ impl RustyPipe {
.ok_or(Error::Auth(AuthError::NoLogin)) .ok_or(Error::Auth(AuthError::NoLogin))
} }
fn user_auth_datasync_id(&self) -> Result<String, Error> {
self.inner
.cache
.auth_cookie
.read()
.unwrap()
.as_ref()
.and_then(|c| c.user_syncid.as_ref().map(|id| id.to_owned()))
.ok_or(Error::Auth(AuthError::NoLogin))
}
/// Set the user authentication cookie /// Set the user authentication cookie
/// ///
/// The cookie is used for authenticated requests with browser-based clients /// The cookie is used for authenticated requests with browser-based clients
@ -1628,17 +1699,17 @@ impl RustyPipe {
))?; ))?;
// datasyncid is of the form "channel_syncid||user_syncid" for secondary channel // datasyncid is of the form "channel_syncid||user_syncid" for secondary channel
// and just "user_syncid||" for primary channel. We only want the channel_syncid // and just "user_syncid||" for primary channel.
let (channel_syncid, user_syncid) = let (p1, p2) =
datasync_id datasync_id
.split_once("||") .split_once("||")
.ok_or(Error::Extraction(ExtractionError::InvalidData( .ok_or(Error::Extraction(ExtractionError::InvalidData(
"datasyncId does not contain || seperator".into(), "datasyncId does not contain || seperator".into(),
)))?; )))?;
auth_cookie.account_syncid = if user_syncid.is_empty() { (auth_cookie.channel_syncid, auth_cookie.user_syncid) = if p2.is_empty() {
None (None, Some(p1.to_owned()))
} else { } else {
Some(channel_syncid.to_owned()) (Some(p1.to_owned()), Some(p2.to_owned()))
}; };
auth_cookie.session_index = Some( auth_cookie.session_index = Some(
@ -1648,6 +1719,11 @@ impl RustyPipe {
); );
Ok(()) Ok(())
} }
/// Get the version string (e.g. `rustypipe-botguard 0.1.1`) of the used botguard binary
pub async fn version_botguard(&self) -> Option<String> {
self.inner.botguard.as_ref().map(|bg| bg.version.to_owned())
}
} }
impl RustyPipeQuery { impl RustyPipeQuery {
@ -1669,6 +1745,22 @@ impl RustyPipeQuery {
self self
} }
/// Set the timezone and its associated UTC offset in minutes used
/// when accessing the YouTube API.
#[must_use]
pub fn timezone<S: Into<String>>(mut self, timezone: S, utc_offset_minutes: i16) -> Self {
self.opts.timezone = Some(timezone.into());
self.opts.utc_offset_minutes = utc_offset_minutes;
self
}
/// Access the YouTube API using the local system timezone
#[must_use]
pub fn timezone_local(self) -> Self {
let (timezone, utc_offset_minutes) = local_tz_offset();
self.timezone(timezone, utc_offset_minutes)
}
/// Generate a report on every operation. /// Generate a report on every operation.
/// ///
/// This should only be used for debugging. /// This should only be used for debugging.
@ -1823,6 +1915,8 @@ impl RustyPipeQuery {
} else { } else {
(Language::En, Country::Us) (Language::En, Country::Us)
}; };
let utc_offset_minutes = self.opts.utc_offset_minutes;
let time_zone = self.opts.timezone.as_deref().unwrap_or("UTC");
match ctype { match ctype {
ClientType::Desktop => YTContext { ClientType::Desktop => YTContext {
@ -1834,6 +1928,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: Some(RequestYT::default()), request: Some(RequestYT::default()),
@ -1849,6 +1945,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: Some(RequestYT::default()), request: Some(RequestYT::default()),
@ -1864,6 +1962,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: Some(RequestYT::default()), request: Some(RequestYT::default()),
@ -1880,6 +1980,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: Some(RequestYT::default()), request: Some(RequestYT::default()),
@ -1899,6 +2001,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: None, request: None,
@ -1916,6 +2020,8 @@ impl RustyPipeQuery {
visitor_data, visitor_data,
hl, hl,
gl, gl,
time_zone,
utc_offset_minutes,
..Default::default() ..Default::default()
}, },
request: None, request: None,
@ -2037,7 +2143,7 @@ impl RustyPipeQuery {
if let Some(session_index) = auth_cookie.session_index { if let Some(session_index) = auth_cookie.session_index {
r = r.header("X-Goog-AuthUser", session_index); r = r.header("X-Goog-AuthUser", session_index);
} }
if let Some(account_syncid) = auth_cookie.account_syncid { if let Some(account_syncid) = auth_cookie.channel_syncid {
r = r.header("X-Goog-PageId", account_syncid); r = r.header("X-Goog-PageId", account_syncid);
} }
cookie = Some(auth_cookie.cookie); cookie = Some(auth_cookie.cookie);
@ -2096,7 +2202,7 @@ impl RustyPipeQuery {
self.client.inner.visitor_data_cache.remove(visitor_data); self.client.inner.visitor_data_cache.remove(visitor_data);
} }
/// Get PO tokens /// Generate PO tokens
async fn get_po_tokens(&self, idents: &[&str]) -> Result<(Vec<String>, OffsetDateTime), Error> { async fn get_po_tokens(&self, idents: &[&str]) -> Result<(Vec<String>, OffsetDateTime), Error> {
let bg = self let bg = self
.client .client
@ -2135,28 +2241,41 @@ impl RustyPipeQuery {
} }
let mut valid_until = None; let mut valid_until = None;
let mut from_snapshot = false;
for word in words { for word in words {
if let Some((k, v)) = word.split_once('=') { if let Some((k, v)) = word.split_once('=') {
if k == "valid_until" { match k {
valid_until = Some( "valid_until" => {
v.parse::<i64>() valid_until = Some(
.ok() v.parse::<i64>()
.and_then(|x| OffsetDateTime::from_unix_timestamp(x).ok()) .ok()
.ok_or(ExtractionError::Botguard( .and_then(|x| OffsetDateTime::from_unix_timestamp(x).ok())
format!("invalid validity date: {v}").into(), .ok_or(ExtractionError::Botguard(
))?, format!("invalid validity date: {v}").into(),
); ))?,
);
}
"from_snapshot" => {
from_snapshot = v.eq_ignore_ascii_case("true") || v == "1";
}
_ => {}
} }
} }
} }
tracing::debug!("generated PO token (took {:?})", start.elapsed()); let valid_until =
Ok(( valid_until.unwrap_or_else(|| OffsetDateTime::now_utc() + time::Duration::hours(12));
tokens,
valid_until.unwrap_or_else(|| OffsetDateTime::now_utc() + time::Duration::hours(12)), tracing::debug!(
)) "generated PO token (valid_until {}, from_snapshot={}, took {}ms)",
valid_until,
from_snapshot,
start.elapsed().as_millis()
);
Ok((tokens, valid_until))
} }
/// Get a session-bound PO token (either from cache or newly generated)
async fn get_session_po_token(&self, visitor_data: &str) -> Result<PoToken, Error> { async fn get_session_po_token(&self, visitor_data: &str) -> Result<PoToken, Error> {
if let Some(po_token) = self.client.inner.visitor_data_cache.get_pot(visitor_data) { if let Some(po_token) = self.client.inner.visitor_data_cache.get_pot(visitor_data) {
return Ok(po_token); return Ok(po_token);
@ -2170,7 +2289,7 @@ impl RustyPipeQuery {
Ok(po_token) Ok(po_token)
} }
/// Get a Proof-of-origin token /// Get a PO token (Proof-of-origin token)
/// ///
/// PO tokens are used by the web-based YouTube clients for requesting player data and video streams. /// PO tokens are used by the web-based YouTube clients for requesting player data and video streams.
/// ///
@ -2184,6 +2303,22 @@ impl RustyPipeQuery {
}) })
} }
/// Get a new RustyPipeInfo object for reports
fn rp_info(&self) -> RustyPipeInfo<'_> {
RustyPipeInfo::new(
Some(self.opts.lang),
self.client
.inner
.botguard
.as_ref()
.map(|bg| bg.version.as_str()),
)
}
/// Execute a request to the YouTube API, then deobfuscate and map the response.
///
/// Runs a single attempt, returns Ok with a erroneous RequestResult in case of a
/// HTTP or mapping error so it can be retried/reported.
async fn execute_request_attempt< async fn execute_request_attempt<
R: DeserializeOwned + MapResponse<M> + Debug, R: DeserializeOwned + MapResponse<M> + Debug,
M, M,
@ -2213,6 +2348,8 @@ impl RustyPipeQuery {
let ctx = MapRespCtx { let ctx = MapRespCtx {
id, id,
lang: self.opts.lang, lang: self.opts.lang,
utc_offset: UtcOffset::from_whole_seconds(i32::from(self.opts.utc_offset_minutes) * 60)
.map_err(|_| Error::Other("utc_offset overflow".into()))?,
deobf: ctx_src.deobf, deobf: ctx_src.deobf,
visitor_data: Some(&visitor_data), visitor_data: Some(&visitor_data),
client_type: ctype, client_type: ctype,
@ -2273,6 +2410,10 @@ impl RustyPipeQuery {
}) })
} }
/// Execute a request to the YouTube API, then deobfuscate and map the response.
///
/// Runs up to n_request_attempts, returns Ok with a erroneous RequestResult in case of a
/// HTTP or mapping error so it can be reported.
async fn execute_request_inner< async fn execute_request_inner<
R: DeserializeOwned + MapResponse<M> + Debug, R: DeserializeOwned + MapResponse<M> + Debug,
M, M,
@ -2286,7 +2427,7 @@ impl RustyPipeQuery {
ctx_src: &MapRespOptions<'_>, ctx_src: &MapRespOptions<'_>,
) -> Result<RequestResult<M>, Error> { ) -> Result<RequestResult<M>, Error> {
let mut last_resp = None; let mut last_resp = None;
for n in 0..=self.client.inner.n_request_attempts { for n in 0..=self.client.inner.n_http_retries {
let resp = self let resp = self
.execute_request_attempt::<R, M, B>(ctype, id, endpoint, body, ctx_src) .execute_request_attempt::<R, M, B>(ctype, id, endpoint, body, ctx_src)
.await?; .await?;
@ -2304,7 +2445,7 @@ impl RustyPipeQuery {
// Remove the used visitor data from cache if the request resulted in a recoverable error // Remove the used visitor data from cache if the request resulted in a recoverable error
self.remove_visitor_data(&resp.visitor_data); self.remove_visitor_data(&resp.visitor_data);
if n != self.client.inner.n_request_attempts { if n != self.client.inner.n_http_retries {
let ms = util::retry_delay(n, 1000, 60000, 3); let ms = util::retry_delay(n, 1000, 60000, 3);
tracing::warn!( tracing::warn!(
"Retry attempt #{}. Error: {}. Waiting {} ms", "Retry attempt #{}. Error: {}. Waiting {} ms",
@ -2379,7 +2520,7 @@ impl RustyPipeQuery {
if level > Level::DBG || self.opts.report { if level > Level::DBG || self.opts.report {
if let Some(reporter) = &self.client.inner.reporter { if let Some(reporter) = &self.client.inner.reporter {
let report = Report { let report = Report {
info: RustyPipeInfo::new(Some(self.opts.lang)), info: self.rp_info(),
level, level,
operation: &format!("{operation}({id})"), operation: &format!("{operation}({id})"),
error, error,
@ -2499,6 +2640,7 @@ impl AsRef<RustyPipeQuery> for RustyPipeQuery {
struct MapRespCtx<'a> { struct MapRespCtx<'a> {
id: &'a str, id: &'a str,
lang: Language, lang: Language,
utc_offset: UtcOffset,
deobf: Option<&'a DeobfData>, deobf: Option<&'a DeobfData>,
visitor_data: Option<&'a str>, visitor_data: Option<&'a str>,
client_type: ClientType, client_type: ClientType,
@ -2526,6 +2668,7 @@ impl<'a> MapRespCtx<'a> {
Self { Self {
id, id,
lang: Language::En, lang: Language::En,
utc_offset: UtcOffset::UTC,
deobf: None, deobf: None,
visitor_data: None, visitor_data: None,
client_type: ClientType::Desktop, client_type: ClientType::Desktop,
@ -2564,6 +2707,59 @@ fn validate_country(country: Country) -> Country {
} }
} }
fn local_tz_offset() -> (String, i16) {
match (
localzone::get_local_zone().ok_or(Error::Other("could not get local timezone".into())),
UtcOffset::current_local_offset().map_err(|_| Error::Other("indeterminate offset".into())),
) {
(Ok(timezone), Ok(offset)) => (timezone, offset.whole_minutes()),
(Err(e), _) | (_, Err(e)) => {
tracing::error!("{e}");
("UTC".to_owned(), 0)
}
}
}
/// Check if a valid Botguard binary is available at the given location
fn detect_botguard_bin(program: OsString) -> Result<(OsString, String), Error> {
let out = std::process::Command::new(&program)
.arg("--version")
.output()
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
Error::Other("rustypipe-botguard binary not found".into())
} else {
Error::Other(format!("error calling rustypipe-botguard {e}").into())
}
})?;
if !out.status.success() {
return Err(Error::Extraction(ExtractionError::Botguard(
format!("version check failed with status {}", out.status).into(),
)));
}
let output = String::from_utf8_lossy(&out.stdout);
let pat = "rustypipe-botguard-api ";
let pos = output.find(pat).ok_or(Error::Other(
"no rustypipe-botguard-api version returned".into(),
))? + pat.len();
let pos_end = output[pos..]
.char_indices()
.find(|(_, c)| !c.is_ascii_digit())
.map(|(p, _)| p + pos)
.unwrap_or(output.len());
let api_version = &output[pos..pos_end];
if api_version != BOTGUARD_API_VERSION {
return Err(Error::Other(
format!(
"incompatible rustypipe-botguard-api version {api_version}, expected {BOTGUARD_API_VERSION}"
)
.into(),
));
}
let version = output[..pos].lines().next().unwrap_or_default().to_owned();
Ok((program, version))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -154,9 +154,24 @@ fn map_artist_page(
ctx: &MapRespCtx<'_>, ctx: &MapRespCtx<'_>,
skip_extendables: bool, skip_extendables: bool,
) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> { ) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> {
// dbg!(&res); let contents = match res.contents {
Some(c) => c,
None => {
if res.microformat.microformat_data_renderer.noindex {
return Err(ExtractionError::NotFound {
id: ctx.id.to_owned(),
msg: "no contents".into(),
});
} else {
return Err(ExtractionError::InvalidData("no contents".into()));
}
}
};
let header = res.header.music_immersive_header_renderer; let header = res
.header
.ok_or(ExtractionError::InvalidData("no header".into()))?
.music_immersive_header_renderer;
if let Some(share) = header.share_endpoint { if let Some(share) = header.share_endpoint {
let pb = share.share_entity_endpoint.serialized_share_entity; let pb = share.share_entity_endpoint.serialized_share_entity;
@ -173,8 +188,7 @@ fn map_artist_page(
} }
} }
let sections = res let sections = contents
.contents
.single_column_browse_results_renderer .single_column_browse_results_renderer
.contents .contents
.into_iter() .into_iter()
@ -338,8 +352,6 @@ impl MapResponse<FirstAlbumPage> for response::MusicArtistAlbums {
self, self,
ctx: &MapRespCtx<'_>, ctx: &MapRespCtx<'_>,
) -> Result<MapResult<FirstAlbumPage>, ExtractionError> { ) -> Result<MapResult<FirstAlbumPage>, ExtractionError> {
// dbg!(&self);
let Some(header) = self.header else { let Some(header) = self.header else {
return Err(ExtractionError::NotFound { return Err(ExtractionError::NotFound {
id: ctx.id.into(), id: ctx.id.into(),

View file

@ -105,8 +105,6 @@ impl MapResponse<Vec<MusicGenreItem>> for response::MusicGenres {
impl MapResponse<MusicGenre> for response::MusicGenre { impl MapResponse<MusicGenre> for response::MusicGenre {
fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<MusicGenre>, ExtractionError> { fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<MusicGenre>, ExtractionError> {
// dbg!(&self);
let content = self let content = self
.contents .contents
.single_column_browse_results_renderer .single_column_browse_results_renderer

View file

@ -9,7 +9,7 @@ use crate::{
AlbumId, ChannelId, MusicAlbum, MusicPlaylist, TrackItem, TrackType, AlbumId, ChannelId, MusicAlbum, MusicPlaylist, TrackItem, TrackType,
}, },
serializer::{text::TextComponents, MapResult}, serializer::{text::TextComponents, MapResult},
util::{self, TryRemove, DOT_SEPARATOR}, util::{self, dictionary, TryRemove, DOT_SEPARATOR},
}; };
use self::response::url_endpoint::MusicPageType; use self::response::url_endpoint::MusicPageType;
@ -87,7 +87,7 @@ impl RustyPipeQuery {
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, track)| { .filter_map(|(i, track)| {
if track.track_type.is_video() { if track.track_type.is_video() && !track.unavailable {
Some((i, track.name.clone())) Some((i, track.name.clone()))
} else { } else {
None None
@ -95,47 +95,61 @@ impl RustyPipeQuery {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !to_replace.is_empty() { let last_tn = album
.tracks
.last()
.and_then(|t| t.track_nr)
.unwrap_or_default();
if !to_replace.is_empty() || last_tn < album.track_count {
tracing::debug!(
"fetching album playlist ({} tracks, {} to replace)",
album.track_count,
to_replace.len()
);
let mut playlist = self.music_playlist(playlist_id).await?; let mut playlist = self.music_playlist(playlist_id).await?;
playlist playlist
.tracks .tracks
.extend_limit(&self, album.tracks.len()) .extend_limit(&self, album.track_count.into())
.await?; .await?;
for (i, title) in to_replace { for (i, title) in to_replace {
let found_track = playlist.tracks.items.iter().find_map(|track| { let found_track = playlist.tracks.items.iter().find_map(|track| {
if track.name == title && track.track_type.is_track() { if track.name == title && track.track_type.is_track() {
Some((track.id.clone(), track.duration)) Some((track.id.clone(), track.duration, track.unavailable))
} else { } else {
None None
} }
}); });
if let Some((track_id, duration)) = found_track { if let Some((track_id, duration, unavailable)) = found_track {
album.tracks[i].id = track_id; album.tracks[i].id = track_id;
if let Some(duration) = duration { if let Some(duration) = duration {
album.tracks[i].duration = Some(duration); album.tracks[i].duration = Some(duration);
} }
album.tracks[i].track_type = TrackType::Track; album.tracks[i].track_type = TrackType::Track;
album.tracks[i].unavailable = unavailable;
}
}
// Extend the list of album tracks with the ones from the playlist if the playlist returned more tracks
// This is the case for albums with more than 200 tracks (e.g. audiobooks)
// Note: in some cases the playlist may contain a loop of repeating tracks. If a track was found in the playlist
// that already exists in the album, stop.
if album.tracks.len() < playlist.tracks.items.len() {
let mut tn = last_tn;
for mut t in playlist.tracks.items.into_iter().skip(album.tracks.len()) {
if album.tracks.iter().any(|at| at.id == t.id) {
break;
}
tn += 1;
t.album = album.tracks.first().and_then(|t| t.album.clone());
t.track_nr = Some(tn);
album.tracks.push(t);
} }
} }
} }
} }
Ok(album) Ok(album)
} }
/// Get all liked YouTube Music tracks of the logged-in user
///
/// The difference to [`RustyPipeQuery::music_saved_tracks`] is that this function only returns
/// tracks that were explicitly liked by the user.
///
/// Requires authentication cookies.
pub async fn music_liked_tracks(&self) -> Result<MusicPlaylist, Error> {
self.clone()
.authenticated()
.music_playlist("LM")
.await
.map_err(util::map_internal_playlist_err)
}
} }
impl MapResponse<MusicPlaylist> for response::MusicPlaylist { impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
@ -143,9 +157,21 @@ impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
self, self,
ctx: &MapRespCtx<'_>, ctx: &MapRespCtx<'_>,
) -> Result<MapResult<MusicPlaylist>, ExtractionError> { ) -> Result<MapResult<MusicPlaylist>, ExtractionError> {
// dbg!(&self); let contents = match self.contents {
Some(c) => c,
None => {
if self.microformat.microformat_data_renderer.noindex {
return Err(ExtractionError::NotFound {
id: ctx.id.to_owned(),
msg: "no contents".into(),
});
} else {
return Err(ExtractionError::InvalidData("no contents".into()));
}
}
};
let (header, music_contents) = match self.contents { let (header, music_contents) = match contents {
response::music_playlist::Contents::SingleColumnBrowseResultsRenderer(c) => ( response::music_playlist::Contents::SingleColumnBrowseResultsRenderer(c) => (
self.header, self.header,
c.contents c.contents
@ -276,8 +302,8 @@ impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
// Album playlists fetched via the playlist method dont include a header // Album playlists fetched via the playlist method dont include a header
let (album, cover) = map_res let (album, cover) = map_res
.c .c
.first() .iter()
.and_then(|t: &TrackItem| { .find_map(|t: &TrackItem| {
t.album.as_ref().map(|a| (a.clone(), t.cover.clone())) t.album.as_ref().map(|a| (a.clone(), t.cover.clone()))
}) })
.ok_or(ExtractionError::InvalidData(Cow::Borrowed( .ok_or(ExtractionError::InvalidData(Cow::Borrowed(
@ -285,10 +311,11 @@ impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
)))?; )))?;
if !map_res.c.iter().all(|t| { if !map_res.c.iter().all(|t| {
t.album t.unavailable
.as_ref() || t.album
.map(|a| a.id == album.id) .as_ref()
.unwrap_or_default() .map(|a| a.id == album.id)
.unwrap_or_default()
}) { }) {
return Err(ExtractionError::InvalidData(Cow::Borrowed( return Err(ExtractionError::InvalidData(Cow::Borrowed(
"album playlist containing items from different albums", "album playlist containing items from different albums",
@ -332,9 +359,21 @@ impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
impl MapResponse<MusicAlbum> for response::MusicPlaylist { impl MapResponse<MusicAlbum> for response::MusicPlaylist {
fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<MusicAlbum>, ExtractionError> { fn map_response(self, ctx: &MapRespCtx<'_>) -> Result<MapResult<MusicAlbum>, ExtractionError> {
// dbg!(&self); let contents = match self.contents {
Some(c) => c,
None => {
if self.microformat.microformat_data_renderer.noindex {
return Err(ExtractionError::NotFound {
id: ctx.id.to_owned(),
msg: "no contents".into(),
});
} else {
return Err(ExtractionError::InvalidData("no contents".into()));
}
}
};
let (header, sections) = match self.contents { let (header, sections) = match contents {
response::music_playlist::Contents::SingleColumnBrowseResultsRenderer(c) => ( response::music_playlist::Contents::SingleColumnBrowseResultsRenderer(c) => (
self.header, self.header,
c.contents c.contents
@ -374,7 +413,18 @@ impl MapResponse<MusicAlbum> for response::MusicPlaylist {
match section { match section {
response::music_item::ItemSection::MusicShelfRenderer(sh) => shelf = Some(sh), response::music_item::ItemSection::MusicShelfRenderer(sh) => shelf = Some(sh),
response::music_item::ItemSection::MusicCarouselShelfRenderer(sh) => { response::music_item::ItemSection::MusicCarouselShelfRenderer(sh) => {
album_variants = Some(sh.contents); if sh
.header
.map(|h| {
h.music_carousel_shelf_basic_header_renderer
.title
.first_str()
== dictionary::entry(ctx.lang).album_versions_title
})
.unwrap_or_default()
{
album_variants = Some(sh.contents);
}
} }
_ => (), _ => (),
} }
@ -439,12 +489,14 @@ impl MapResponse<MusicAlbum> for response::MusicPlaylist {
} }
} }
let playlist_id = self.microformat.and_then(|mf| { let playlist_id = self
mf.microformat_data_renderer .microformat
.url_canonical .microformat_data_renderer
.strip_prefix("https://music.youtube.com/playlist?list=") .url_canonical
.map(str::to_owned) .and_then(|x| {
}); x.strip_prefix("https://music.youtube.com/playlist?list=")
.map(str::to_owned)
});
let (playlist_id, artist_id) = header let (playlist_id, artist_id) = header
.menu .menu
.or_else(|| header.buttons.into_iter().next()) .or_else(|| header.buttons.into_iter().next())
@ -471,6 +523,14 @@ impl MapResponse<MusicAlbum> for response::MusicPlaylist {
.unwrap_or_default(); .unwrap_or_default();
let artist_id = artist_id.or_else(|| artists.first().and_then(|a| a.id.clone())); let artist_id = artist_id.or_else(|| artists.first().and_then(|a| a.id.clone()));
let second_subtitle_parts = header
.second_subtitle
.split(|p| p == DOT_SEPARATOR)
.collect::<Vec<_>>();
let track_count = second_subtitle_parts
.get(usize::from(second_subtitle_parts.len() > 2))
.and_then(|txt| util::parse_numeric::<u16>(&txt[0]).ok());
let mut mapper = MusicListMapper::with_album( let mut mapper = MusicListMapper::with_album(
ctx.lang, ctx.lang,
artists.clone(), artists.clone(),
@ -505,6 +565,7 @@ impl MapResponse<MusicAlbum> for response::MusicPlaylist {
album_type, album_type,
year, year,
by_va, by_va,
track_count: track_count.unwrap_or(tracks_res.c.len() as u16),
tracks: tracks_res.c, tracks: tracks_res.c,
variants: variants_res.c, variants: variants_res.c,
}, },
@ -555,8 +616,8 @@ mod tests {
#[case::single("single", "MPREb_bHfHGoy7vuv")] #[case::single("single", "MPREb_bHfHGoy7vuv")]
#[case::description("description", "MPREb_PiyfuVl6aYd")] #[case::description("description", "MPREb_PiyfuVl6aYd")]
#[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")] #[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")]
#[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")]
#[case::two_columns("20240228_twoColumns", "MPREb_bHfHGoy7vuv")] #[case::two_columns("20240228_twoColumns", "MPREb_bHfHGoy7vuv")]
#[case::recommends("20250225_recommends", "MPREb_u1I69lSAe5v")]
fn map_music_album(#[case] name: &str, #[case] id: &str) { fn map_music_album(#[case] name: &str, #[case] id: &str) {
let json_path = path!(*TESTFILES / "music_playlist" / format!("album_{name}.json")); let json_path = path!(*TESTFILES / "music_playlist" / format!("album_{name}.json"));
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();

View file

@ -155,8 +155,6 @@ impl<T: FromYtItem> MapResponse<MusicSearchResult<T>> for response::MusicSearch
self, self,
ctx: &MapRespCtx<'_>, ctx: &MapRespCtx<'_>,
) -> Result<MapResult<MusicSearchResult<T>>, ExtractionError> { ) -> Result<MapResult<MusicSearchResult<T>>, ExtractionError> {
// dbg!(&self);
let tabs = self.contents.tabbed_search_results_renderer.contents; let tabs = self.contents.tabbed_search_results_renderer.contents;
let sections = tabs let sections = tabs
.into_iter() .into_iter()

View file

@ -8,7 +8,7 @@ use crate::{
error::{Error, ExtractionError}, error::{Error, ExtractionError},
model::{ model::{
paginator::{ContinuationEndpoint, Paginator}, paginator::{ContinuationEndpoint, Paginator},
AlbumItem, ArtistItem, HistoryItem, MusicPlaylistItem, TrackItem, AlbumItem, ArtistItem, HistoryItem, MusicPlaylist, MusicPlaylistItem, TrackItem,
}, },
serializer::MapResult, serializer::MapResult,
}; };
@ -127,6 +127,20 @@ impl RustyPipeQuery {
) )
.await .await
} }
/// Get all liked YouTube Music tracks of the logged-in user
///
/// The difference to [`RustyPipeQuery::music_saved_tracks`] is that this function only returns
/// tracks that were explicitly liked by the user.
///
/// Requires authentication cookies.
pub async fn music_liked_tracks(&self) -> Result<MusicPlaylist, Error> {
self.clone()
.authenticated()
.music_playlist("LM")
.await
.map_err(crate::util::map_internal_playlist_err)
}
} }
impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicHistory { impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicHistory {
@ -160,7 +174,7 @@ impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicHistory {
}; };
let mut mapper = MusicListMapper::new(ctx.lang); let mut mapper = MusicListMapper::new(ctx.lang);
mapper.map_response(shelf.contents); mapper.map_response(shelf.contents);
mapper.conv_history_items(shelf.title, &mut map_res); mapper.conv_history_items(shelf.title, ctx.utc_offset, &mut map_res);
} }
let ctoken = contents let ctoken = contents
@ -195,7 +209,7 @@ mod tests {
#[test] #[test]
fn map_history() { fn map_history() {
let json_path = path!(*TESTFILES / "music_history" / "music_history.json"); let json_path = path!(*TESTFILES / "music_userdata" / "music_history.json");
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
let history: response::MusicHistory = let history: response::MusicHistory =

View file

@ -6,12 +6,15 @@ use crate::model::{
traits::FromYtItem, traits::FromYtItem,
Comment, MusicItem, YouTubeItem, Comment, MusicItem, YouTubeItem,
}; };
use crate::model::{HistoryItem, TrackItem, VideoItem};
use crate::serializer::MapResult; use crate::serializer::MapResult;
use self::response::YouTubeListItem; #[cfg(feature = "userdata")]
use crate::model::{HistoryItem, TrackItem, VideoItem};
use super::response::music_item::{map_queue_item, MusicListMapper, PlaylistPanelVideo}; use super::response::{
music_item::{map_queue_item, MusicListMapper, PlaylistPanelVideo},
YouTubeListItem,
};
use super::{ use super::{
response, ClientType, MapRespCtx, MapRespOptions, MapResponse, QContinuation, RustyPipeQuery, response, ClientType, MapRespCtx, MapRespOptions, MapResponse, QContinuation, RustyPipeQuery,
}; };
@ -225,6 +228,7 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
} }
} }
#[cfg(feature = "userdata")]
impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::Continuation { impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::Continuation {
fn map_response( fn map_response(
self, self,
@ -241,14 +245,13 @@ impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::Continuation {
mapper.map_response(contents); mapper.map_response(contents);
mapper.conv_history_items( mapper.conv_history_items(
header.map(|h| h.item_section_header_renderer.title), header.map(|h| h.item_section_header_renderer.title),
ctx.utc_offset,
&mut map_res, &mut map_res,
); );
} }
response::YouTubeListItem::ContinuationItemRenderer { response::YouTubeListItem::ContinuationItemRenderer(ep) => {
continuation_endpoint,
} => {
if ctoken.is_none() { if ctoken.is_none() {
ctoken = Some(continuation_endpoint.continuation_command.token); ctoken = ep.continuation_endpoint.into_token();
} }
} }
_ => {} _ => {}
@ -269,6 +272,7 @@ impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::Continuation {
} }
} }
#[cfg(feature = "userdata")]
impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicContinuation { impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicContinuation {
fn map_response( fn map_response(
self, self,
@ -280,7 +284,7 @@ impl MapResponse<Paginator<HistoryItem<TrackItem>>> for response::MusicContinuat
let mut map_shelf = |shelf: response::music_item::MusicShelf| { let mut map_shelf = |shelf: response::music_item::MusicShelf| {
let mut mapper = MusicListMapper::new(ctx.lang); let mut mapper = MusicListMapper::new(ctx.lang);
mapper.map_response(shelf.contents); mapper.map_response(shelf.contents);
mapper.conv_history_items(shelf.title, &mut map_res); mapper.conv_history_items(shelf.title, ctx.utc_offset, &mut map_res);
continuations.extend(shelf.continuations); continuations.extend(shelf.continuations);
}; };
@ -421,6 +425,8 @@ impl Paginator<Comment> {
} }
} }
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
impl Paginator<HistoryItem<VideoItem>> { impl Paginator<HistoryItem<VideoItem>> {
/// Get the next page from the paginator (or `None` if the paginator is exhausted) /// Get the next page from the paginator (or `None` if the paginator is exhausted)
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> { pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
@ -436,6 +442,8 @@ impl Paginator<HistoryItem<VideoItem>> {
} }
} }
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
impl Paginator<HistoryItem<TrackItem>> { impl Paginator<HistoryItem<TrackItem>> {
/// Get the next page from the paginator (or `None` if the paginator is exhausted) /// Get the next page from the paginator (or `None` if the paginator is exhausted)
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> { pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
@ -532,7 +540,11 @@ macro_rules! paginator {
} }
paginator!(Comment); paginator!(Comment);
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
paginator!(HistoryItem<VideoItem>); paginator!(HistoryItem<VideoItem>);
#[cfg(feature = "userdata")]
#[cfg_attr(docsrs, doc(cfg(feature = "userdata")))]
paginator!(HistoryItem<TrackItem>); paginator!(HistoryItem<TrackItem>);
#[cfg(test)] #[cfg(test)]
@ -619,7 +631,7 @@ mod tests {
} }
#[rstest] #[rstest]
#[case::subscriptions("subscriptions", path!("history" / "subscriptions.json"))] #[case::subscriptions("subscriptions", path!("userdata" / "subscriptions.json"))]
fn map_continuation_channels(#[case] name: &str, #[case] path: PathBuf) { fn map_continuation_channels(#[case] name: &str, #[case] path: PathBuf) {
let json_path = path!(*TESTFILES / path); let json_path = path!(*TESTFILES / path);
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
@ -643,7 +655,7 @@ mod tests {
#[case::playlist_tracks("playlist_tracks", path!("music_playlist" / "playlist_cont.json"))] #[case::playlist_tracks("playlist_tracks", path!("music_playlist" / "playlist_cont.json"))]
#[case::search_tracks("search_tracks", path!("music_search" / "tracks_cont.json"))] #[case::search_tracks("search_tracks", path!("music_search" / "tracks_cont.json"))]
#[case::radio_tracks("radio_tracks", path!("music_details" / "radio_cont.json"))] #[case::radio_tracks("radio_tracks", path!("music_details" / "radio_cont.json"))]
#[case::saved_tracks("saved_tracks", path!("music_history" / "saved_tracks.json"))] #[case::saved_tracks("saved_tracks", path!("music_userdata" / "saved_tracks.json"))]
fn map_continuation_tracks(#[case] name: &str, #[case] path: PathBuf) { fn map_continuation_tracks(#[case] name: &str, #[case] path: PathBuf) {
let json_path = path!(*TESTFILES / path); let json_path = path!(*TESTFILES / path);
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
@ -664,7 +676,7 @@ mod tests {
} }
#[rstest] #[rstest]
#[case::saved_artists("saved_artists", path!("music_history" / "saved_artists.json"))] #[case::saved_artists("saved_artists", path!("music_userdata" / "saved_artists.json"))]
fn map_continuation_artists(#[case] name: &str, #[case] path: PathBuf) { fn map_continuation_artists(#[case] name: &str, #[case] path: PathBuf) {
let json_path = path!(*TESTFILES / path); let json_path = path!(*TESTFILES / path);
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
@ -685,7 +697,7 @@ mod tests {
} }
#[rstest] #[rstest]
#[case::saved_albums("saved_albums", path!("music_history" / "saved_albums.json"))] #[case::saved_albums("saved_albums", path!("music_userdata" / "saved_albums.json"))]
fn map_continuation_albums(#[case] name: &str, #[case] path: PathBuf) { fn map_continuation_albums(#[case] name: &str, #[case] path: PathBuf) {
let json_path = path!(*TESTFILES / path); let json_path = path!(*TESTFILES / path);
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
@ -707,7 +719,7 @@ mod tests {
#[rstest] #[rstest]
#[case::playlist_related("playlist_related", path!("music_playlist" / "playlist_related.json"))] #[case::playlist_related("playlist_related", path!("music_playlist" / "playlist_related.json"))]
#[case::saved_playlists("saved_playlists", path!("music_history" / "saved_playlists.json"))] #[case::saved_playlists("saved_playlists", path!("music_userdata" / "saved_playlists.json"))]
fn map_continuation_music_playlists(#[case] name: &str, #[case] path: PathBuf) { fn map_continuation_music_playlists(#[case] name: &str, #[case] path: PathBuf) {
let json_path = path!(*TESTFILES / path); let json_path = path!(*TESTFILES / path);
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();

View file

@ -1,6 +1,6 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap, HashSet},
fmt::Debug, fmt::Debug,
}; };
@ -104,42 +104,29 @@ impl RustyPipeQuery {
) -> Result<VideoPlayer, Error> { ) -> Result<VideoPlayer, Error> {
let video_id = video_id.as_ref(); let video_id = video_id.as_ref();
let mut last_e = None; let mut last_e = None;
let mut query = Cow::Borrowed(self);
let mut clients_iter = clients.iter().peekable(); let mut clients_iter = clients.iter().peekable();
let mut failed_clients = HashSet::new();
while let Some(client) = clients_iter.next() { while let Some(client) = clients_iter.next() {
if self.opts.auth == Some(true) && !self.auth_enabled(*client) { if query.opts.auth == Some(true) && !self.auth_enabled(*client) {
// If no client has auth enabled, return NoLogin error instead of "no clients" // If no client has auth enabled, return NoLogin error instead of "no clients"
if last_e.is_none() { if last_e.is_none() {
last_e = Some(Error::Auth(AuthError::NoLogin)); last_e = Some(Error::Auth(AuthError::NoLogin));
} }
continue; continue;
} }
if failed_clients.contains(client) {
continue;
}
let res = self.player_from_client(video_id, *client).await; let res = query.player_from_client(video_id, *client).await;
match res { match res {
Ok(res) => return Ok(res), Ok(res) => return Ok(res),
Err(Error::Extraction(e)) => { Err(Error::Extraction(e)) => {
if e.use_login() { if e.use_login() && query.opts.auth.is_none() {
if let Some(c) = self.auth_enabled_client(clients) { clients_iter = clients.iter().peekable();
tracing::info!("{e}; fetching player with login"); query = Cow::Owned(self.clone().authenticated());
match self
.clone()
.authenticated()
.player_from_client(video_id, c)
.await
{
Ok(res) => return Ok(res),
Err(Error::Extraction(e)) => {
if !e.switch_client() {
return Err(Error::Extraction(e));
}
}
Err(e) => return Err(e),
}
} else {
return Err(Error::Extraction(e));
}
} else if !e.switch_client() { } else if !e.switch_client() {
return Err(Error::Extraction(e)); return Err(Error::Extraction(e));
} }
@ -147,6 +134,7 @@ impl RustyPipeQuery {
tracing::warn!("error fetching player with {client:?} client: {e}; retrying with {next_client:?} client"); tracing::warn!("error fetching player with {client:?} client: {e}; retrying with {next_client:?} client");
} }
last_e = Some(Error::Extraction(e)); last_e = Some(Error::Extraction(e));
failed_clients.insert(*client);
} }
Err(e) => return Err(e), Err(e) => return Err(e),
} }
@ -156,22 +144,27 @@ impl RustyPipeQuery {
async fn get_player_po_token(&self, video_id: &str) -> Result<PlayerPoToken, Error> { async fn get_player_po_token(&self, video_id: &str) -> Result<PlayerPoToken, Error> {
if let Some(bg) = &self.client.inner.botguard { if let Some(bg) = &self.client.inner.botguard {
let visitor_data = self.get_visitor_data(false).await?; let (ident, visitor_data) = if self.opts.auth == Some(true) {
(self.client.user_auth_datasync_id()?, None)
} else {
let visitor_data = self.get_visitor_data(false).await?;
(visitor_data.to_owned(), Some(visitor_data))
};
if bg.po_token_cache { if bg.po_token_cache {
let session_token = self.get_session_po_token(&visitor_data).await?; let session_token = self.get_session_po_token(&ident).await?;
Ok(PlayerPoToken { Ok(PlayerPoToken {
visitor_data: Some(visitor_data), visitor_data,
session_po_token: Some(session_token), session_po_token: Some(session_token),
content_po_token: None, content_po_token: None,
}) })
} else { } else {
let (po_tokens, valid_until) = let (po_tokens, valid_until) = self.get_po_tokens(&[video_id, &ident]).await?;
self.get_po_tokens(&[video_id, &visitor_data]).await?;
let mut po_tokens = po_tokens.into_iter(); let mut po_tokens = po_tokens.into_iter();
let po_token = po_tokens.next().unwrap(); let po_token = po_tokens.next().unwrap();
let session_po_token = po_tokens.next().unwrap(); let session_po_token = po_tokens.next().unwrap();
Ok(PlayerPoToken { Ok(PlayerPoToken {
visitor_data: Some(visitor_data), visitor_data,
session_po_token: Some(PoToken { session_po_token: Some(PoToken {
po_token: session_po_token, po_token: session_po_token,
valid_until, valid_until,
@ -191,6 +184,11 @@ impl RustyPipeQuery {
video_id: S, video_id: S,
client_type: ClientType, client_type: ClientType,
) -> Result<VideoPlayer, Error> { ) -> Result<VideoPlayer, Error> {
if self.opts.auth == Some(true) {
tracing::info!("fetching {client_type:?} player with login");
} else {
tracing::debug!("fetching {client_type:?} player");
}
let video_id = video_id.as_ref(); let video_id = video_id.as_ref();
let (deobf, player_po) = tokio::try_join!( let (deobf, player_po) = tokio::try_join!(
@ -309,24 +307,28 @@ impl MapResponse<VideoPlayer> for response::Player {
error_screen, error_screen,
} => { } => {
let mut msg = reason; let mut msg = reason;
if let Some(error_screen) = error_screen { if let Some(error_screen) = error_screen.player_error_message_renderer {
msg.push_str(" - "); msg.push_str(" - ");
msg.push_str(&error_screen.player_error_message_renderer.subreason); msg.push_str(&error_screen.subreason);
} }
let reason = msg let reason = if error_screen.player_captcha_view_model.is_some() {
.split_whitespace() UnavailabilityReason::Captcha
.find_map(|word| match word { } else {
"payment" => Some(UnavailabilityReason::Paid), msg.split_whitespace()
"Premium" => Some(UnavailabilityReason::Premium), .find_map(|word| match word {
"members-only" => Some(UnavailabilityReason::MembersOnly), "payment" => Some(UnavailabilityReason::Paid),
"country" => Some(UnavailabilityReason::Geoblocked), "Premium" => Some(UnavailabilityReason::Premium),
"version" | "websites" => Some(UnavailabilityReason::UnsupportedClient), "members-only" => Some(UnavailabilityReason::MembersOnly),
"bot" => Some(UnavailabilityReason::IpBan), "country" => Some(UnavailabilityReason::Geoblocked),
"later." => Some(UnavailabilityReason::TryAgain), "version" | "websites" => Some(UnavailabilityReason::UnsupportedClient),
_ => None, "bot" => Some(UnavailabilityReason::IpBan),
}) "VPN/Proxy" => Some(UnavailabilityReason::VpnBan),
.unwrap_or_default(); "later." => Some(UnavailabilityReason::TryAgain),
_ => None,
})
.unwrap_or_default()
};
return Err(ExtractionError::Unavailable { reason, msg }); return Err(ExtractionError::Unavailable { reason, msg });
} }
response::player::PlayabilityStatus::LoginRequired { reason, messages } => { response::player::PlayabilityStatus::LoginRequired { reason, messages } => {
@ -385,6 +387,21 @@ impl MapResponse<VideoPlayer> for response::Player {
video_details.video_id, ctx.id video_details.video_id, ctx.id
))); )));
} }
// Sometimes YouTube Desktop does not output any URLs for adaptive streams.
// Since this is currently rare, it is best to retry the request in this case.
if !is_live
&& !streaming_data.adaptive_formats.c.is_empty()
&& streaming_data
.adaptive_formats
.c
.iter()
.all(|f| f.url.is_none() && f.signature_cipher.is_none())
{
return Err(ExtractionError::Unavailable {
reason: UnavailabilityReason::TryAgain,
msg: "no adaptive stream URLs".to_owned(),
});
}
let video_info = VideoPlayerDetails { let video_info = VideoPlayerDetails {
id: video_details.video_id, id: video_details.video_id,
@ -627,7 +644,7 @@ impl<'a> StreamsMapper<'a> {
fn deobf(&self) -> Result<&Deobfuscator, DeobfError> { fn deobf(&self) -> Result<&Deobfuscator, DeobfError> {
self.deobf self.deobf
.as_ref() .as_ref()
.ok_or(DeobfError::Other("no deobfuscator")) .ok_or(DeobfError::Other("no deobfuscator".into()))
} }
fn cipher_to_url_params( fn cipher_to_url_params(
@ -937,6 +954,7 @@ mod tests {
use path_macro::path; use path_macro::path;
use rstest::rstest; use rstest::rstest;
use time::UtcOffset;
use super::*; use super::*;
use crate::{deobfuscate::DeobfData, param::Language, util::tests::TESTFILES}; use crate::{deobfuscate::DeobfData, param::Language, util::tests::TESTFILES};
@ -968,6 +986,7 @@ mod tests {
.map_response(&MapRespCtx { .map_response(&MapRespCtx {
id: "pPvd8UxmSbQ", id: "pPvd8UxmSbQ",
lang: Language::En, lang: Language::En,
utc_offset: UtcOffset::UTC,
deobf: Some(&DEOBF_DATA), deobf: Some(&DEOBF_DATA),
visitor_data: None, visitor_data: None,
client_type, client_type,

View file

@ -33,28 +33,6 @@ impl RustyPipeQuery {
) )
.await .await
} }
/// Get all liked videos of the logged-in user
///
/// Requires authentication cookies.
pub async fn liked_videos(&self) -> Result<Playlist, Error> {
self.clone()
.authenticated()
.playlist("LL")
.await
.map_err(util::map_internal_playlist_err)
}
/// Get the "Watch later" playlist of the logged-in user
///
/// Requires authentication cookies.
pub async fn watch_later(&self) -> Result<Playlist, Error> {
self.clone()
.authenticated()
.playlist("WL")
.await
.map_err(util::map_internal_playlist_err)
}
} }
impl MapResponse<Playlist> for response::Playlist { impl MapResponse<Playlist> for response::Playlist {
@ -162,10 +140,10 @@ impl MapResponse<Playlist> for response::Playlist {
.next() .next()
.and_then(|r| r.metadata_parts.into_iter().next()) .and_then(|r| r.metadata_parts.into_iter().next())
.and_then(|p| match p { .and_then(|p| match p {
response::MetadataPart::Text(_) => None, response::MetadataPart::Text { .. } => None,
response::MetadataPart::AvatarStack { response::MetadataPart::AvatarStack { avatar_stack } => {
avatar_stack_view_model, ChannelId::try_from(avatar_stack.avatar_stack_view_model.text).ok()
} => ChannelId::try_from(avatar_stack_view_model.text).ok(), }
}); });
// remove "by" prefix // remove "by" prefix
if let Some(c) = channel.as_mut() { if let Some(c) = channel.as_mut() {
@ -225,8 +203,13 @@ impl MapResponse<Playlist> for response::Playlist {
.as_deref() .as_deref()
.or(last_update_txt2.as_deref()) .or(last_update_txt2.as_deref())
.and_then(|txt| { .and_then(|txt| {
timeago::parse_textual_date_or_warn(ctx.lang, txt, &mut mapper.warnings) timeago::parse_textual_date_or_warn(
.map(OffsetDateTime::date) ctx.lang,
ctx.utc_offset,
txt,
&mut mapper.warnings,
)
.map(OffsetDateTime::date)
}); });
Ok(MapResult { Ok(MapResult {
@ -274,6 +257,7 @@ mod tests {
#[case::nomusic("nomusic", "PL1J-6JOckZtE_P9Xx8D3b2O6w0idhuKBe")] #[case::nomusic("nomusic", "PL1J-6JOckZtE_P9Xx8D3b2O6w0idhuKBe")]
#[case::live("live", "UULVvqRdlKsE5Q8mf8YXbdIJLw")] #[case::live("live", "UULVvqRdlKsE5Q8mf8YXbdIJLw")]
#[case::pageheader("20241011_pageheader", "PLT2w2oBf1TZKyvY_M6JsASs73m-wjLzH5")] #[case::pageheader("20241011_pageheader", "PLT2w2oBf1TZKyvY_M6JsASs73m-wjLzH5")]
#[case::cmdexecutor("20250316_cmdexecutor", "PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")]
fn map_playlist_data(#[case] name: &str, #[case] id: &str) { fn map_playlist_data(#[case] name: &str, #[case] id: &str) {
let json_path = path!(*TESTFILES / "playlist" / format!("playlist_{name}.json")); let json_path = path!(*TESTFILES / "playlist" / format!("playlist_{name}.json"));
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();

View file

@ -1,10 +1,8 @@
pub(crate) mod channel; pub(crate) mod channel;
pub(crate) mod history;
pub(crate) mod music_artist; pub(crate) mod music_artist;
pub(crate) mod music_charts; pub(crate) mod music_charts;
pub(crate) mod music_details; pub(crate) mod music_details;
pub(crate) mod music_genres; pub(crate) mod music_genres;
pub(crate) mod music_history;
pub(crate) mod music_item; pub(crate) mod music_item;
pub(crate) mod music_new; pub(crate) mod music_new;
pub(crate) mod music_playlist; pub(crate) mod music_playlist;
@ -19,7 +17,6 @@ pub(crate) mod video_item;
pub(crate) use channel::Channel; pub(crate) use channel::Channel;
pub(crate) use channel::ChannelAbout; pub(crate) use channel::ChannelAbout;
pub(crate) use history::History;
pub(crate) use music_artist::MusicArtist; pub(crate) use music_artist::MusicArtist;
pub(crate) use music_artist::MusicArtistAlbums; pub(crate) use music_artist::MusicArtistAlbums;
pub(crate) use music_charts::MusicCharts; pub(crate) use music_charts::MusicCharts;
@ -28,7 +25,6 @@ pub(crate) use music_details::MusicLyrics;
pub(crate) use music_details::MusicRelated; pub(crate) use music_details::MusicRelated;
pub(crate) use music_genres::MusicGenre; pub(crate) use music_genres::MusicGenre;
pub(crate) use music_genres::MusicGenres; pub(crate) use music_genres::MusicGenres;
pub(crate) use music_history::MusicHistory;
pub(crate) use music_item::MusicContinuation; pub(crate) use music_item::MusicContinuation;
pub(crate) use music_new::MusicNew; pub(crate) use music_new::MusicNew;
pub(crate) use music_playlist::MusicPlaylist; pub(crate) use music_playlist::MusicPlaylist;
@ -51,6 +47,15 @@ pub(crate) mod channel_rss;
#[cfg(feature = "rss")] #[cfg(feature = "rss")]
pub(crate) use channel_rss::ChannelRss; pub(crate) use channel_rss::ChannelRss;
#[cfg(feature = "userdata")]
pub(crate) mod history;
#[cfg(feature = "userdata")]
pub(crate) use history::History;
#[cfg(feature = "userdata")]
pub(crate) mod music_history;
#[cfg(feature = "userdata")]
pub(crate) use music_history::MusicHistory;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -147,9 +152,16 @@ pub(crate) struct ContinuationItemRenderer {
pub continuation_endpoint: ContinuationEndpoint, pub continuation_endpoint: ContinuationEndpoint,
} }
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub(crate) enum ContinuationEndpoint {
ContinuationCommand(ContinuationCommandWrap),
CommandExecutorCommand(CommandExecutorCommandWrap),
}
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct ContinuationEndpoint { pub(crate) struct ContinuationCommandWrap {
pub continuation_command: ContinuationCommand, pub continuation_command: ContinuationCommand,
} }
@ -159,7 +171,34 @@ pub(crate) struct ContinuationCommand {
pub token: String, pub token: String,
} }
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CommandExecutorCommandWrap {
pub command_executor_command: CommandExecutorCommand,
}
#[serde_as] #[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CommandExecutorCommand {
#[serde_as(as = "VecSkipError<_>")]
commands: Vec<ContinuationCommandWrap>,
}
impl ContinuationEndpoint {
pub fn into_token(self) -> Option<String> {
match self {
Self::ContinuationCommand(cmd) => Some(cmd.continuation_command.token),
Self::CommandExecutorCommand(cmd) => cmd
.command_executor_command
.commands
.into_iter()
.next()
.map(|c| c.continuation_command.token),
}
}
}
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct Icon { pub(crate) struct Icon {
@ -608,31 +647,36 @@ pub(crate) struct PhMetadataRow {
#[serde_as] #[serde_as]
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(untagged)]
pub(crate) enum MetadataPart { pub(crate) enum MetadataPart {
Text(#[serde_as(as = "AttributedText")] TextComponent), Text {
#[serde(rename_all = "camelCase")] #[serde_as(as = "AttributedText")]
AvatarStack { text: TextComponent,
avatar_stack_view_model: TextComponentBox,
}, },
#[serde(rename_all = "camelCase")]
AvatarStack { avatar_stack: AvatarStackInner },
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct AvatarStackInner {
pub avatar_stack_view_model: TextComponentBox,
} }
impl MetadataPart { impl MetadataPart {
pub fn into_text_component(self) -> TextComponent { pub fn into_text_component(self) -> TextComponent {
match self { match self {
MetadataPart::Text(text_component) => text_component, MetadataPart::Text { text } => text,
MetadataPart::AvatarStack { MetadataPart::AvatarStack { avatar_stack } => avatar_stack.avatar_stack_view_model.text,
avatar_stack_view_model,
} => avatar_stack_view_model.text,
} }
} }
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
match self { match self {
MetadataPart::Text(s) => s.as_str(), MetadataPart::Text { text } => text.as_str(),
MetadataPart::AvatarStack { MetadataPart::AvatarStack { avatar_stack } => {
avatar_stack_view_model, avatar_stack.avatar_stack_view_model.text.as_str()
} => avatar_stack_view_model.text.as_str(), }
} }
} }
} }

View file

@ -5,7 +5,8 @@ use crate::serializer::text::Text;
use super::{ use super::{
music_item::{ music_item::{
Button, Grid, ItemSection, MusicThumbnailRenderer, SimpleHeader, SingleColumnBrowseResult, Button, Grid, ItemSection, MusicMicroformat, MusicThumbnailRenderer, SimpleHeader,
SingleColumnBrowseResult,
}, },
SectionList, Tab, SectionList, Tab,
}; };
@ -14,8 +15,10 @@ use super::{
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicArtist { pub(crate) struct MusicArtist {
pub contents: SingleColumnBrowseResult<Tab<SectionList<ItemSection>>>, pub contents: Option<SingleColumnBrowseResult<Tab<SectionList<ItemSection>>>>,
pub header: Header, pub header: Option<Header>,
#[serde(default)]
pub microformat: MusicMicroformat,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]

View file

@ -4,7 +4,7 @@ use serde_with::{rust::deserialize_ignore_any, serde_as, DefaultOnError, VecSkip
use crate::{ use crate::{
model::{ model::{
self, traits::FromYtItem, AlbumId, AlbumItem, AlbumType, ArtistId, ArtistItem, ChannelId, self, traits::FromYtItem, AlbumId, AlbumItem, AlbumType, ArtistId, ArtistItem, ChannelId,
HistoryItem, MusicItem, MusicItemType, MusicPlaylistItem, TrackItem, UserItem, MusicItem, MusicItemType, MusicPlaylistItem, TrackItem, UserItem,
}, },
param::Language, param::Language,
serializer::{ serializer::{
@ -22,6 +22,11 @@ use super::{
SimpleHeaderRenderer, Thumbnails, ThumbnailsWrap, SimpleHeaderRenderer, Thumbnails, ThumbnailsWrap,
}; };
#[cfg(feature = "userdata")]
use crate::model::HistoryItem;
#[cfg(feature = "userdata")]
use time::UtcOffset;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) enum ItemSection { pub(crate) enum ItemSection {
@ -39,6 +44,7 @@ pub(crate) enum ItemSection {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicShelf { pub(crate) struct MusicShelf {
#[cfg(feature = "userdata")]
#[serde_as(as = "Option<Text>")] #[serde_as(as = "Option<Text>")]
pub title: Option<String>, pub title: Option<String>,
/// Playlist ID (only for playlists) /// Playlist ID (only for playlists)
@ -427,6 +433,22 @@ pub(crate) enum TrackBadge {
LiveBadgeRenderer {}, LiveBadgeRenderer {},
} }
#[serde_as]
#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct MusicMicroformat {
#[serde_as(as = "DefaultOnError")]
pub microformat_data_renderer: MicroformatData,
}
#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct MicroformatData {
pub url_canonical: Option<String>,
#[serde(default)]
pub noindex: bool,
}
/* /*
#MAPPER #MAPPER
*/ */
@ -524,7 +546,9 @@ impl MusicListMapper {
MusicResponseItem::ContinuationItemRenderer { MusicResponseItem::ContinuationItemRenderer {
continuation_endpoint, continuation_endpoint,
} => { } => {
self.ctoken = Some(continuation_endpoint.continuation_command.token); if self.ctoken.is_none() {
self.ctoken = continuation_endpoint.into_token();
}
Ok(None) Ok(None)
} }
} }
@ -773,6 +797,7 @@ impl MusicListMapper {
track_type: vtype.into(), track_type: vtype.into(),
track_nr, track_nr,
by_va, by_va,
unavailable: item.music_item_renderer_display_policy == DisplayPolicy::GreyOut,
})); }));
Ok(Some(MusicItemType::Track)) Ok(Some(MusicItemType::Track))
} }
@ -953,6 +978,7 @@ impl MusicListMapper {
track_type: vtype.into(), track_type: vtype.into(),
track_nr: None, track_nr: None,
by_va, by_va,
unavailable: false,
})); }));
Ok(Some(MusicItemType::Track)) Ok(Some(MusicItemType::Track))
} }
@ -1117,6 +1143,7 @@ impl MusicListMapper {
track_type: vtype.into(), track_type: vtype.into(),
track_nr: None, track_nr: None,
by_va, by_va,
unavailable: false,
})); }));
} else { } else {
let (artists, by_va) = map_artists(subtitle_p2); let (artists, by_va) = map_artists(subtitle_p2);
@ -1154,6 +1181,7 @@ impl MusicListMapper {
track_type: vtype.into(), track_type: vtype.into(),
track_nr: None, track_nr: None,
by_va, by_va,
unavailable: false,
})); }));
} }
Some(MusicItemType::Track) Some(MusicItemType::Track)
@ -1269,9 +1297,11 @@ impl MusicListMapper {
} }
} }
#[cfg(feature = "userdata")]
pub fn conv_history_items( pub fn conv_history_items(
self, self,
date_txt: Option<String>, date_txt: Option<String>,
utc_offset: UtcOffset,
res: &mut MapResult<Vec<HistoryItem<TrackItem>>>, res: &mut MapResult<Vec<HistoryItem<TrackItem>>>,
) { ) {
res.warnings.extend(self.warnings); res.warnings.extend(self.warnings);
@ -1282,7 +1312,12 @@ impl MusicListMapper {
.map(|item| HistoryItem { .map(|item| HistoryItem {
item, item,
playback_date: date_txt.as_deref().and_then(|s| { playback_date: date_txt.as_deref().and_then(|s| {
timeago::parse_textual_date_to_d(self.lang, s, &mut res.warnings) timeago::parse_textual_date_to_d(
self.lang,
utc_offset,
s,
&mut res.warnings,
)
}), }),
playback_date_txt: date_txt.clone(), playback_date_txt: date_txt.clone(),
}), }),
@ -1404,6 +1439,7 @@ pub(crate) fn map_queue_item(item: QueueMusicItem, lang: Language) -> MapResult<
track_type: MusicVideoType::from_is_video(is_video).into(), track_type: MusicVideoType::from_is_video(is_video).into(),
track_nr: None, track_nr: None,
by_va, by_va,
unavailable: false,
}, },
warnings, warnings,
} }

View file

@ -5,22 +5,21 @@ use crate::serializer::text::{AttributedText, Text, TextComponents};
use super::{ use super::{
music_item::{ music_item::{
Button, ItemSection, MusicContentsRenderer, MusicItemMenuEntry, MusicThumbnailRenderer, Button, ItemSection, MusicContentsRenderer, MusicItemMenuEntry, MusicMicroformat,
MusicThumbnailRenderer,
}, },
url_endpoint::OnTapWrap, url_endpoint::OnTapWrap,
ContentsRenderer, SectionList, Tab, ContentsRenderer, SectionList, Tab,
}; };
/// Response model for YouTube Music playlists and albums /// Response model for YouTube Music playlists and albums
#[serde_as]
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicPlaylist { pub(crate) struct MusicPlaylist {
pub contents: Contents, pub contents: Option<Contents>,
pub header: Option<Header>, pub header: Option<Header>,
#[serde(default)] #[serde(default)]
#[serde_as(as = "DefaultOnError")] pub microformat: MusicMicroformat,
pub microformat: Option<Microformat>,
} }
#[serde_as] #[serde_as]
@ -162,15 +161,3 @@ pub(crate) struct AvatarStackViewModel {
pub(crate) struct AvatarStackRendererContext { pub(crate) struct AvatarStackRendererContext {
pub command_context: Option<OnTapWrap>, pub command_context: Option<OnTapWrap>,
} }
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Microformat {
pub microformat_data_renderer: MicroformatData,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct MicroformatData {
pub url_canonical: String,
}

View file

@ -37,8 +37,7 @@ pub(crate) enum PlayabilityStatus {
#[serde(default)] #[serde(default)]
reason: String, reason: String,
#[serde(default)] #[serde(default)]
#[serde_as(deserialize_as = "DefaultOnError")] error_screen: ErrorScreen,
error_screen: Option<ErrorScreen>,
}, },
/// Age limit / Private video /// Age limit / Private video
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -61,14 +60,18 @@ pub(crate) enum PlayabilityStatus {
}, },
} }
#[derive(Debug, Deserialize)] #[serde_as]
#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct ErrorScreen { pub(crate) struct ErrorScreen {
pub player_error_message_renderer: ErrorMessage, #[serde(default)]
#[serde_as(deserialize_as = "DefaultOnError")]
pub player_error_message_renderer: Option<ErrorMessage>,
pub player_captcha_view_model: Option<Empty>,
} }
#[serde_as] #[serde_as]
#[derive(Debug, Deserialize)] #[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct ErrorMessage { pub(crate) struct ErrorMessage {
#[serde_as(as = "Text")] #[serde_as(as = "Text")]

View file

@ -530,15 +530,14 @@ pub(crate) enum ContinuationItemVariants {
} }
impl ContinuationItemVariants { impl ContinuationItemVariants {
pub fn token(self) -> String { pub fn into_token(self) -> Option<String> {
match self { match self {
ContinuationItemVariants::Ep { ContinuationItemVariants::Ep {
continuation_endpoint, continuation_endpoint,
} => continuation_endpoint, } => continuation_endpoint,
ContinuationItemVariants::Btn { button } => button.button_renderer.command, ContinuationItemVariants::Btn { button } => button.button_renderer.command,
} }
.continuation_command .into_token()
.token
} }
} }

View file

@ -4,12 +4,9 @@ use serde_with::{
}; };
use time::OffsetDateTime; use time::OffsetDateTime;
use super::{ use super::{ChannelBadge, ContentImage, ContinuationItemRenderer, PhMetadataView, Thumbnails};
ChannelBadge, ContentImage, ContinuationEndpoint, PhMetadataView, SimpleHeaderRenderer,
Thumbnails,
};
use crate::{ use crate::{
model::{Channel, ChannelItem, ChannelTag, HistoryItem, PlaylistItem, VideoItem, YouTubeItem}, model::{Channel, ChannelItem, ChannelTag, PlaylistItem, VideoItem, YouTubeItem},
param::Language, param::Language,
serializer::{ serializer::{
text::{AttributedText, Text, TextComponent}, text::{AttributedText, Text, TextComponent},
@ -18,6 +15,11 @@ use crate::{
util::{self, timeago, TryRemove}, util::{self, timeago, TryRemove},
}; };
#[cfg(feature = "userdata")]
use crate::{client::response::SimpleHeaderRenderer, model::HistoryItem};
#[cfg(feature = "userdata")]
use time::UtcOffset;
#[serde_as] #[serde_as]
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -35,12 +37,9 @@ pub(crate) enum YouTubeListItem {
LockupViewModel(LockupViewModel), LockupViewModel(LockupViewModel),
/// Continauation items are located at the end of a list /// Continuation items are located at the end of a list
/// and contain the continuation token for progressive loading /// and contain the continuation token for progressive loading
#[serde(rename_all = "camelCase")] ContinuationItemRenderer(ContinuationItemRenderer),
ContinuationItemRenderer {
continuation_endpoint: ContinuationEndpoint,
},
/// Corrected search query /// Corrected search query
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -66,6 +65,7 @@ pub(crate) enum YouTubeListItem {
/// GridRenderer: contains videos on channel page /// GridRenderer: contains videos on channel page
#[serde(alias = "expandedShelfContentsRenderer", alias = "gridRenderer")] #[serde(alias = "expandedShelfContentsRenderer", alias = "gridRenderer")]
ItemSectionRenderer { ItemSectionRenderer {
#[cfg(feature = "userdata")]
header: Option<ItemSectionHeader>, header: Option<ItemSectionHeader>,
#[serde(alias = "items")] #[serde(alias = "items")]
contents: MapResult<Vec<YouTubeListItem>>, contents: MapResult<Vec<YouTubeListItem>>,
@ -298,6 +298,7 @@ pub(crate) struct YouTubeListRenderer {
pub contents: MapResult<Vec<YouTubeListItem>>, pub contents: MapResult<Vec<YouTubeListItem>>,
} }
#[cfg(feature = "userdata")]
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct ItemSectionHeader { pub(crate) struct ItemSectionHeader {
@ -786,7 +787,7 @@ impl<T> YouTubeListMapper<T> {
thumbnail: tn.image.into(), thumbnail: tn.image.into(),
channel, channel,
publish_date: publish_date_txt.as_deref().and_then(|t| { publish_date: publish_date_txt.as_deref().and_then(|t| {
timeago::parse_textual_date_or_warn(self.lang, t, &mut self.warnings) timeago::parse_timeago_dt_or_warn(self.lang, t, &mut self.warnings)
}), }),
publish_date_txt, publish_date_txt,
view_count, view_count,
@ -834,9 +835,11 @@ impl YouTubeListMapper<YouTubeItem> {
self.items.push(mapped); self.items.push(mapped);
} }
} }
YouTubeListItem::ContinuationItemRenderer { YouTubeListItem::ContinuationItemRenderer(r) => {
continuation_endpoint, if self.ctoken.is_none() {
} => self.ctoken = Some(continuation_endpoint.continuation_command.token), self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => { YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query); self.corrected_query = Some(corrected_query);
} }
@ -882,9 +885,11 @@ impl YouTubeListMapper<VideoItem> {
self.items.push(mapped); self.items.push(mapped);
} }
} }
YouTubeListItem::ContinuationItemRenderer { YouTubeListItem::ContinuationItemRenderer(r) => {
continuation_endpoint, if self.ctoken.is_none() {
} => self.ctoken = Some(continuation_endpoint.continuation_command.token), self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => { YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query); self.corrected_query = Some(corrected_query);
} }
@ -904,20 +909,20 @@ impl YouTubeListMapper<VideoItem> {
res.c.into_iter().for_each(|item| self.map_item(item)); res.c.into_iter().for_each(|item| self.map_item(item));
} }
#[cfg(feature = "userdata")]
pub(crate) fn conv_history_items( pub(crate) fn conv_history_items(
self, self,
date_txt: Option<String>, date_txt: Option<String>,
utc_offset: UtcOffset,
res: &mut MapResult<Vec<HistoryItem<VideoItem>>>, res: &mut MapResult<Vec<HistoryItem<VideoItem>>>,
) { ) {
res.warnings.extend(self.warnings); res.warnings.extend(self.warnings);
res.c.extend(self.items.into_iter().map(|item| { res.c.extend(self.items.into_iter().map(|item| HistoryItem {
HistoryItem { item,
item, playback_date: date_txt.as_deref().and_then(|s| {
playback_date: date_txt.as_deref().and_then(|s| { timeago::parse_textual_date_to_d(self.lang, utc_offset, s, &mut res.warnings)
timeago::parse_textual_date_to_d(self.lang, s, &mut res.warnings) }),
}), playback_date_txt: date_txt.clone(),
playback_date_txt: date_txt.clone(),
}
})); }));
} }
} }
@ -934,9 +939,11 @@ impl YouTubeListMapper<PlaylistItem> {
self.items.push(mapped); self.items.push(mapped);
} }
} }
YouTubeListItem::ContinuationItemRenderer { YouTubeListItem::ContinuationItemRenderer(r) => {
continuation_endpoint, if self.ctoken.is_none() {
} => self.ctoken = Some(continuation_endpoint.continuation_command.token), self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => { YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query); self.corrected_query = Some(corrected_query);
} }

View file

@ -7,7 +7,7 @@ Channel(
name: "EEVblog", name: "EEVblog",
handle: Some("@EEVblog"), handle: Some("@EEVblog"),
subscriber_count: Some(952000), subscriber_count: Some(952000),
video_count: Some(2), video_count: Some(2000),
avatar: [ avatar: [
Thumbnail( Thumbnail(
url: "https://yt3.googleusercontent.com/ytc/AIdro_l17lYcTcRSydZeQK-RuiSfEeH5eX9m4irSNQj6109v5MQ=s72-c-k-c0x00ffffff-no-rj", url: "https://yt3.googleusercontent.com/ytc/AIdro_l17lYcTcRSydZeQK-RuiSfEeH5eX9m4irSNQj6109v5MQ=s72-c-k-c0x00ffffff-no-rj",

View file

@ -7,7 +7,7 @@ Channel(
name: "EEVblog", name: "EEVblog",
handle: Some("@EEVblog"), handle: Some("@EEVblog"),
subscriber_count: Some(933000), subscriber_count: Some(933000),
video_count: Some(19), video_count: Some(1900),
avatar: [ avatar: [
Thumbnail( Thumbnail(
url: "https://yt3.googleusercontent.com/ytc/AIdro_lagjGDfXbXlQXhznx3CDRitOBdxvebllQd_YP1ag=s72-c-k-c0x00ffffff-no-rj", url: "https://yt3.googleusercontent.com/ytc/AIdro_lagjGDfXbXlQXhznx3CDRitOBdxvebllQd_YP1ag=s72-c-k-c0x00ffffff-no-rj",

View file

@ -52,6 +52,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "h3T_NXRUUjM", id: "h3T_NXRUUjM",
@ -84,6 +85,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XZfoFwWvkGQ", id: "XZfoFwWvkGQ",
@ -116,6 +118,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "LOuVxwVFJhs", id: "LOuVxwVFJhs",
@ -148,6 +151,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "GePZUYeIQQQ", id: "GePZUYeIQQQ",
@ -180,6 +184,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0mcING0Zdis", id: "0mcING0Zdis",
@ -209,6 +214,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EAC-2ttHCyk", id: "EAC-2ttHCyk",
@ -238,6 +244,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Bret5VaVzJk", id: "Bret5VaVzJk",
@ -267,6 +274,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EqP1_IcjW-s", id: "EqP1_IcjW-s",
@ -296,6 +304,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3EoF9Of98e4", id: "3EoF9Of98e4",
@ -325,6 +334,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qr0eN_uIcTs", id: "qr0eN_uIcTs",
@ -354,6 +364,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "McgSyiug6XE", id: "McgSyiug6XE",
@ -387,6 +398,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ioZxvVhjFs8", id: "ioZxvVhjFs8",
@ -416,6 +428,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3jyZJEcomkw", id: "3jyZJEcomkw",
@ -445,6 +458,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9oM-cflYhGk", id: "9oM-cflYhGk",
@ -474,6 +488,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -67,6 +67,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xTvyyoF_LZY", id: "xTvyyoF_LZY",
@ -99,6 +100,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SlbfAYvA_gI", id: "SlbfAYvA_gI",
@ -131,6 +133,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fdz_cabS9BU", id: "fdz_cabS9BU",
@ -163,6 +166,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hJWSZDJb-W4", id: "hJWSZDJb-W4",
@ -195,6 +199,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fezKpDFKf5U", id: "fezKpDFKf5U",
@ -224,6 +229,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "doGzjheI604", id: "doGzjheI604",
@ -253,6 +259,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zjEdX8-3CD8", id: "zjEdX8-3CD8",
@ -282,6 +289,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DQZcxN9v0RA", id: "DQZcxN9v0RA",
@ -311,6 +319,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2Vv-BfVoq4g", id: "2Vv-BfVoq4g",
@ -340,6 +349,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JGwWNGJdvx8", id: "JGwWNGJdvx8",
@ -369,6 +379,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nSDgHBxUbVQ", id: "nSDgHBxUbVQ",
@ -398,6 +409,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lp-EO5I60KA", id: "lp-EO5I60KA",
@ -427,6 +439,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "orJSJGHjBLI", id: "orJSJGHjBLI",
@ -456,6 +469,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Il0S8BoucSA", id: "Il0S8BoucSA",
@ -485,6 +499,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -67,6 +67,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xTvyyoF_LZY", id: "xTvyyoF_LZY",
@ -99,6 +100,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SlbfAYvA_gI", id: "SlbfAYvA_gI",
@ -131,6 +133,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fdz_cabS9BU", id: "fdz_cabS9BU",
@ -163,6 +166,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hJWSZDJb-W4", id: "hJWSZDJb-W4",
@ -195,6 +199,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fezKpDFKf5U", id: "fezKpDFKf5U",
@ -224,6 +229,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "doGzjheI604", id: "doGzjheI604",
@ -253,6 +259,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zjEdX8-3CD8", id: "zjEdX8-3CD8",
@ -282,6 +289,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DQZcxN9v0RA", id: "DQZcxN9v0RA",
@ -311,6 +319,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2Vv-BfVoq4g", id: "2Vv-BfVoq4g",
@ -340,6 +349,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JGwWNGJdvx8", id: "JGwWNGJdvx8",
@ -369,6 +379,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nSDgHBxUbVQ", id: "nSDgHBxUbVQ",
@ -398,6 +409,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lp-EO5I60KA", id: "lp-EO5I60KA",
@ -427,6 +439,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "orJSJGHjBLI", id: "orJSJGHjBLI",
@ -456,6 +469,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Il0S8BoucSA", id: "Il0S8BoucSA",
@ -485,6 +499,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -67,6 +67,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uZpH7EQ_PwE", id: "uZpH7EQ_PwE",
@ -99,6 +100,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WmQHSkjgyDM", id: "WmQHSkjgyDM",
@ -143,6 +145,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9ssQKlLxBdQ", id: "9ssQKlLxBdQ",
@ -175,6 +178,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "y4FiCl-tUJc", id: "y4FiCl-tUJc",
@ -207,6 +211,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KSav7HayxtI", id: "KSav7HayxtI",
@ -236,6 +241,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7wtfhZwyrcc", id: "7wtfhZwyrcc",
@ -265,6 +271,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TO-_3tck2tg", id: "TO-_3tck2tg",
@ -294,6 +301,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "D9G1VOjN_84", id: "D9G1VOjN_84",
@ -323,6 +331,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fKopy74weus", id: "fKopy74weus",
@ -352,6 +361,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mWRsgZuwf_8", id: "mWRsgZuwf_8",
@ -381,6 +391,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ktvTqknDobU", id: "ktvTqknDobU",
@ -410,6 +421,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "I-QfPUz1es8", id: "I-QfPUz1es8",
@ -434,6 +446,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0I647GU3Jsc", id: "0I647GU3Jsc",
@ -463,6 +476,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gOsM-DYAEhY", id: "gOsM-DYAEhY",
@ -492,6 +506,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -67,6 +67,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7_Bav4c7UGM", id: "7_Bav4c7UGM",
@ -99,6 +100,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kzUZABVj5UQ", id: "kzUZABVj5UQ",
@ -131,6 +133,7 @@ MusicArtist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "P5uE7KDkDFE", id: "P5uE7KDkDFE",
@ -160,6 +163,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kxjZwdLWFrc", id: "kxjZwdLWFrc",
@ -189,6 +193,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-aneeaddeXc", id: "-aneeaddeXc",
@ -218,6 +223,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YWijFdsj_Ew", id: "YWijFdsj_Ew",
@ -247,6 +253,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "N217ZuMQnfY", id: "N217ZuMQnfY",
@ -276,6 +283,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "STNyxlYFyVY", id: "STNyxlYFyVY",
@ -305,6 +313,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "v5KZ5dalhzU", id: "v5KZ5dalhzU",
@ -334,6 +343,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vaSSdzgDNw0", id: "vaSSdzgDNw0",
@ -363,6 +373,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Rq_JkcROjsI", id: "Rq_JkcROjsI",
@ -392,6 +403,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5VNZWTzJFso", id: "5VNZWTzJFso",
@ -421,6 +433,7 @@ MusicArtist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -36,6 +36,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UhbixyxgsiU", id: "UhbixyxgsiU",
@ -65,6 +66,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "saGYMhApaH8", id: "saGYMhApaH8",
@ -94,6 +96,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8n5dJwWXrbo", id: "8n5dJwWXrbo",
@ -123,6 +126,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Cr8K88UcO0s", id: "Cr8K88UcO0s",
@ -152,6 +156,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pfxyk1glEq4", id: "pfxyk1glEq4",
@ -181,6 +186,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VtKcDwz6hiM", id: "VtKcDwz6hiM",
@ -210,6 +216,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aAkMkVFwAoo", id: "aAkMkVFwAoo",
@ -239,6 +246,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3V8aen7Flhs", id: "3V8aen7Flhs",
@ -268,6 +276,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rb0bjyt1OD0", id: "rb0bjyt1OD0",
@ -297,6 +306,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-1vsm5bhoyE", id: "-1vsm5bhoyE",
@ -326,6 +336,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ao3SN7fkQQU", id: "ao3SN7fkQQU",
@ -359,6 +370,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "J9QwBwUnhQo", id: "J9QwBwUnhQo",
@ -388,6 +400,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WyhU6Zb_fhY", id: "WyhU6Zb_fhY",
@ -417,6 +430,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aV-pJ8BBxj8", id: "aV-pJ8BBxj8",
@ -454,6 +468,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gSeBZqcTHLc", id: "gSeBZqcTHLc",
@ -483,6 +498,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Vzkr-G1QEh8", id: "Vzkr-G1QEh8",
@ -512,6 +528,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SK37InR9j38", id: "SK37InR9j38",
@ -545,6 +562,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "C2YSX4sV_bA", id: "C2YSX4sV_bA",
@ -574,6 +592,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ca48oMV59LU", id: "ca48oMV59LU",
@ -603,6 +622,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TUbmIriJlp4", id: "TUbmIriJlp4",
@ -636,6 +656,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Z02zptUN8gI", id: "Z02zptUN8gI",
@ -669,6 +690,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Uq9gPaIzbe8", id: "Uq9gPaIzbe8",
@ -702,6 +724,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "b1kbLwvqugk", id: "b1kbLwvqugk",
@ -731,6 +754,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VF-FGf_ZZiI", id: "VF-FGf_ZZiI",
@ -760,6 +784,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Om0rYw6qzb8", id: "Om0rYw6qzb8",
@ -793,6 +818,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PrSBuEFdRFU", id: "PrSBuEFdRFU",
@ -826,6 +852,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9YdgldMKGGU", id: "9YdgldMKGGU",
@ -855,6 +882,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kiUIkL4aZ5o", id: "kiUIkL4aZ5o",
@ -884,6 +912,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mTkPFsVC5NE", id: "mTkPFsVC5NE",
@ -917,6 +946,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YsMB0i5YTOc", id: "YsMB0i5YTOc",
@ -946,6 +976,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3CkLMG5NwUg", id: "3CkLMG5NwUg",
@ -975,6 +1006,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9yvzvUgzxxg", id: "9yvzvUgzxxg",
@ -1004,6 +1036,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gPCCYMeXin0", id: "gPCCYMeXin0",
@ -1033,6 +1066,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gkkuezo7kX4", id: "gkkuezo7kX4",
@ -1070,6 +1104,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "D2nyu8d7Sq0", id: "D2nyu8d7Sq0",
@ -1099,6 +1134,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SXrcyqCPu4E", id: "SXrcyqCPu4E",
@ -1128,6 +1164,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "p38WgakuYDo", id: "p38WgakuYDo",
@ -1157,6 +1194,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "n4Z1cpdkgQU", id: "n4Z1cpdkgQU",
@ -1186,6 +1224,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4F_vcZ6KD9Q", id: "4F_vcZ6KD9Q",
@ -1215,6 +1254,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
trending_tracks: [ trending_tracks: [
@ -1241,6 +1281,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UhbixyxgsiU", id: "UhbixyxgsiU",
@ -1265,6 +1306,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zugAhfd2r0g", id: "zugAhfd2r0g",
@ -1289,6 +1331,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5jJJYYaw8vw", id: "5jJJYYaw8vw",
@ -1317,6 +1360,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VMZefv4Vrwg", id: "VMZefv4Vrwg",
@ -1341,6 +1385,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3V8aen7Flhs", id: "3V8aen7Flhs",
@ -1365,6 +1410,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rb0bjyt1OD0", id: "rb0bjyt1OD0",
@ -1389,6 +1435,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ut1OzEVUiM4", id: "Ut1OzEVUiM4",
@ -1413,6 +1460,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rAr3-Pn9yRI", id: "rAr3-Pn9yRI",
@ -1437,6 +1485,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PtPewTyPmUg", id: "PtPewTyPmUg",
@ -1461,6 +1510,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "G6xgMW7U0aY", id: "G6xgMW7U0aY",
@ -1485,6 +1535,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "C2YSX4sV_bA", id: "C2YSX4sV_bA",
@ -1509,6 +1560,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kiUIkL4aZ5o", id: "kiUIkL4aZ5o",
@ -1533,6 +1585,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9YdgldMKGGU", id: "9YdgldMKGGU",
@ -1557,6 +1610,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Z02zptUN8gI", id: "Z02zptUN8gI",
@ -1585,6 +1639,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "S0_888ZjlAA", id: "S0_888ZjlAA",
@ -1609,6 +1664,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "J9QwBwUnhQo", id: "J9QwBwUnhQo",
@ -1633,6 +1689,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DWRj2BB8YHs", id: "DWRj2BB8YHs",
@ -1665,6 +1722,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hX0aI5Jz8i8", id: "hX0aI5Jz8i8",
@ -1689,6 +1747,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Dw9VmOLwxoM", id: "Dw9VmOLwxoM",
@ -1713,6 +1772,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
artists: [ artists: [

View file

@ -32,6 +32,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jEdfjuG0Fx4", id: "jEdfjuG0Fx4",
@ -65,6 +66,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pRpeEdMmmQ0", id: "pRpeEdMmmQ0",
@ -94,6 +96,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Gzs60iBgd3E", id: "Gzs60iBgd3E",
@ -127,6 +130,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "sABN7goDbZ8", id: "sABN7goDbZ8",
@ -160,6 +164,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "saGYMhApaH8", id: "saGYMhApaH8",
@ -189,6 +194,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zuVV9Y55gvc", id: "zuVV9Y55gvc",
@ -222,6 +228,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TiM_TFpT_DE", id: "TiM_TFpT_DE",
@ -251,6 +258,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WcIcVapfqXw", id: "WcIcVapfqXw",
@ -284,6 +292,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Cr8K88UcO0s", id: "Cr8K88UcO0s",
@ -313,6 +322,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BddP6PYo2gs", id: "BddP6PYo2gs",
@ -342,6 +352,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "POe9SOEKotk", id: "POe9SOEKotk",
@ -371,6 +382,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Z02zptUN8gI", id: "Z02zptUN8gI",
@ -404,6 +416,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "e8laLiWolGg", id: "e8laLiWolGg",
@ -445,6 +458,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SK37InR9j38", id: "SK37InR9j38",
@ -478,6 +492,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5kJMtNWUytY", id: "5kJMtNWUytY",
@ -507,6 +522,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gQlMMD8auMs", id: "gQlMMD8auMs",
@ -536,6 +552,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "D0gWr9K8Lb4", id: "D0gWr9K8Lb4",
@ -565,6 +582,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7ouFkoU8Ap8", id: "7ouFkoU8Ap8",
@ -594,6 +612,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-1vsm5bhoyE", id: "-1vsm5bhoyE",
@ -623,6 +642,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gnMdTTeY1FY", id: "gnMdTTeY1FY",
@ -652,6 +672,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ca48oMV59LU", id: "ca48oMV59LU",
@ -681,6 +702,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VtKcDwz6hiM", id: "VtKcDwz6hiM",
@ -710,6 +732,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5g2hT4GmAGU", id: "5g2hT4GmAGU",
@ -739,6 +762,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CQLsdm1ZYAw", id: "CQLsdm1ZYAw",
@ -772,6 +796,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UhbixyxgsiU", id: "UhbixyxgsiU",
@ -801,6 +826,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mxF58TYuPaM", id: "mxF58TYuPaM",
@ -830,6 +856,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8n5dJwWXrbo", id: "8n5dJwWXrbo",
@ -859,6 +886,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "j5y6xLpRwx4", id: "j5y6xLpRwx4",
@ -892,6 +920,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jRxDUsGmwuc", id: "jRxDUsGmwuc",
@ -921,6 +950,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RgKAFK5djSk", id: "RgKAFK5djSk",
@ -950,6 +980,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TGtWWb9emYI", id: "TGtWWb9emYI",
@ -979,6 +1010,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "no0RhhdJMlE", id: "no0RhhdJMlE",
@ -1008,6 +1040,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dzsuE5ugxf4", id: "dzsuE5ugxf4",
@ -1037,6 +1070,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aAkMkVFwAoo", id: "aAkMkVFwAoo",
@ -1066,6 +1100,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jpYkoa-uE_c", id: "jpYkoa-uE_c",
@ -1103,6 +1138,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "A_g3lMcWVy0", id: "A_g3lMcWVy0",
@ -1136,6 +1172,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gIOyB9ZXn8s", id: "gIOyB9ZXn8s",
@ -1169,6 +1206,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "MwpMEbgC7DA", id: "MwpMEbgC7DA",
@ -1198,6 +1236,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AJleGCGFyIg", id: "AJleGCGFyIg",
@ -1227,6 +1266,7 @@ MusicCharts(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
trending_tracks: [], trending_tracks: [],

View file

@ -36,6 +36,7 @@ TrackDetails(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
lyrics_id: Some("MPLYt_wrKjTn9hmry"), lyrics_id: Some("MPLYt_wrKjTn9hmry"),
related_id: Some("MPTRt_wrKjTn9hmry"), related_id: Some("MPTRt_wrKjTn9hmry"),

View file

@ -54,6 +54,7 @@ TrackDetails(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
lyrics_id: Some("MPLYt_4xbv14CiQJm-1"), lyrics_id: Some("MPLYt_4xbv14CiQJm-1"),
related_id: Some("MPTRt_4xbv14CiQJm-1"), related_id: Some("MPTRt_4xbv14CiQJm-1"),

View file

@ -38,6 +38,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Y8JFxS1HlDo", id: "Y8JFxS1HlDo",
@ -72,6 +73,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CM4CkVFmTds", id: "CM4CkVFmTds",
@ -106,6 +108,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_ysomCGaZLw", id: "_ysomCGaZLw",
@ -140,6 +143,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gQlMMD8auMs", id: "gQlMMD8auMs",
@ -174,6 +178,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uR8Mrt1IpXg", id: "uR8Mrt1IpXg",
@ -208,6 +213,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PkKnp4SdE-w", id: "PkKnp4SdE-w",
@ -242,6 +248,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4vbDFu0PUew", id: "4vbDFu0PUew",
@ -276,6 +283,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "A5H8zBb3iao", id: "A5H8zBb3iao",
@ -310,6 +318,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_xJUCsyMQes", id: "_xJUCsyMQes",
@ -339,6 +348,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "n0j5NPptyM0", id: "n0j5NPptyM0",
@ -373,6 +383,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3GWscde8rM8", id: "3GWscde8rM8",
@ -407,6 +418,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uBY1AoiF5Vo", id: "uBY1AoiF5Vo",
@ -441,6 +453,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WPdWvnAAurg", id: "WPdWvnAAurg",
@ -475,6 +488,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tyrVtwE8Gv0", id: "tyrVtwE8Gv0",
@ -509,6 +523,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Jh4QFaPmdss", id: "Jh4QFaPmdss",
@ -543,6 +558,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2OvyA2__Eas", id: "2OvyA2__Eas",
@ -577,6 +593,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dYRITmpFbJ4", id: "dYRITmpFbJ4",
@ -611,6 +628,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "POe9SOEKotk", id: "POe9SOEKotk",
@ -645,6 +663,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pSudEWBAYRE", id: "pSudEWBAYRE",
@ -679,6 +698,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nnVjsos40qk", id: "nnVjsos40qk",
@ -713,6 +733,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "H69tJmsgd9I", id: "H69tJmsgd9I",
@ -747,6 +768,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0IBSemQmno8", id: "0IBSemQmno8",
@ -781,6 +803,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "MjCZfZfucEc", id: "MjCZfZfucEc",
@ -810,6 +833,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tg2uF3R_Ozo", id: "tg2uF3R_Ozo",
@ -844,6 +868,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("CBkSSBILdGcydUYzUl9Pem8iEVJEQU1WTVplZXJybnVMaTVFMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0MFp6SjFSak5TWDA5NmJ3"), ctoken: Some("CBkSSBILdGcydUYzUl9Pem8iEVJEQU1WTVplZXJybnVMaTVFMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0MFp6SjFSak5TWDA5NmJ3"),

View file

@ -56,6 +56,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "u1uvv_yKhH8", id: "u1uvv_yKhH8",
@ -108,6 +109,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QiziJ40kTz0", id: "QiziJ40kTz0",
@ -160,6 +162,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OXWz_x6-dro", id: "OXWz_x6-dro",
@ -212,6 +215,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ghrlZIMDzbM", id: "ghrlZIMDzbM",
@ -264,6 +268,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "04tYkKUPPv4", id: "04tYkKUPPv4",
@ -316,6 +321,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wjCrjR5WpgQ", id: "wjCrjR5WpgQ",
@ -368,6 +374,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wkVlb8rSies", id: "wkVlb8rSies",
@ -420,6 +427,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RdU3F5vN3_s", id: "RdU3F5vN3_s",
@ -472,6 +480,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "950BdJKBhGo", id: "950BdJKBhGo",
@ -524,6 +533,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "W0x7GcZkvH4", id: "W0x7GcZkvH4",
@ -576,6 +586,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0EK_M2taRIM", id: "0EK_M2taRIM",
@ -628,6 +639,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "INLFlN-PZq4", id: "INLFlN-PZq4",
@ -680,6 +692,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8JXc4idKS_c", id: "8JXc4idKS_c",
@ -732,6 +745,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vFFT1iAUNDE", id: "vFFT1iAUNDE",
@ -788,6 +802,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g92HIac9ufA", id: "g92HIac9ufA",
@ -840,6 +855,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CinJhZF5ZuA", id: "CinJhZF5ZuA",
@ -892,6 +908,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "t7hmovsG_f0", id: "t7hmovsG_f0",
@ -944,6 +961,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FrEDny55ch8", id: "FrEDny55ch8",
@ -996,6 +1014,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PyyT5tHbOLw", id: "PyyT5tHbOLw",
@ -1048,6 +1067,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_ZkUb7iIOqQ", id: "_ZkUb7iIOqQ",
@ -1100,6 +1120,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UxZH9lRdLD0", id: "UxZH9lRdLD0",
@ -1152,6 +1173,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aYlXNpaQydk", id: "aYlXNpaQydk",
@ -1204,6 +1226,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SZiwpL62to8", id: "SZiwpL62to8",
@ -1256,6 +1279,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mbg1Cn6Ua9U", id: "mbg1Cn6Ua9U",
@ -1308,6 +1332,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("CBkSSBILbWJnMUNuNlVhOVUiEVJEQU1WTTduaWdYUVMxWGIwMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0dFltY3hRMjQyVldFNVZR"), ctoken: Some("CBkSSBILbWJnMUNuNlVhOVUiEVJEQU1WTTduaWdYUVMxWGIwMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0dFltY3hRMjQyVldFNVZR"),

View file

@ -35,6 +35,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g92HIac9ufA", id: "g92HIac9ufA",
@ -67,6 +68,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "khgCIMs_lVQ", id: "khgCIMs_lVQ",
@ -99,6 +101,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "i2VGa-ETiM4", id: "i2VGa-ETiM4",
@ -131,6 +134,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "INLFlN-PZq4", id: "INLFlN-PZq4",
@ -163,6 +167,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ZzbNM2l-AAA", id: "ZzbNM2l-AAA",
@ -195,6 +200,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "i4loHXi8f3A", id: "i4loHXi8f3A",
@ -227,6 +233,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "miqQAzOXPBo", id: "miqQAzOXPBo",
@ -259,6 +266,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hh5GKVa8VtM", id: "hh5GKVa8VtM",
@ -291,6 +299,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dzwSnvfKEtw", id: "dzwSnvfKEtw",
@ -323,6 +332,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "REmUidcJt5I", id: "REmUidcJt5I",
@ -355,6 +365,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OXWz_x6-dro", id: "OXWz_x6-dro",
@ -387,6 +398,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aFoqCI75WoY", id: "aFoqCI75WoY",
@ -419,6 +431,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_Pm74XignKI", id: "_Pm74XignKI",
@ -451,6 +464,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-uOShlFu1v8", id: "-uOShlFu1v8",
@ -483,6 +497,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "LP9sF1v-vz4", id: "LP9sF1v-vz4",
@ -515,6 +530,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KJrPsT2X-yk", id: "KJrPsT2X-yk",
@ -547,6 +563,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tkzYyEp4zB4", id: "tkzYyEp4zB4",
@ -579,6 +596,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ZpD59tu5_Rk", id: "ZpD59tu5_Rk",
@ -611,6 +629,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_eNXeEx9Hvk", id: "_eNXeEx9Hvk",
@ -643,6 +662,7 @@ MusicRelated(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
other_versions: [ other_versions: [
@ -669,6 +689,7 @@ MusicRelated(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Yi2nsnpw5h0", id: "Yi2nsnpw5h0",
@ -693,6 +714,7 @@ MusicRelated(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2Qefh0W_H88", id: "2Qefh0W_H88",
@ -717,6 +739,7 @@ MusicRelated(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "oo89OQvzkIo", id: "oo89OQvzkIo",
@ -741,6 +764,7 @@ MusicRelated(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
albums: [ albums: [

View file

@ -31,6 +31,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gFERoNpcnFU", id: "gFERoNpcnFU",
@ -60,6 +61,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bmEzom5sfCI", id: "bmEzom5sfCI",
@ -89,6 +91,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QHY2pm7uT3k", id: "QHY2pm7uT3k",
@ -118,6 +121,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Su42LK7I4NM", id: "Su42LK7I4NM",
@ -147,6 +151,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mly7ha04bEE", id: "mly7ha04bEE",
@ -176,6 +181,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "c91bmLbGt-g", id: "c91bmLbGt-g",
@ -213,6 +219,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "IwzkfMmNMpM", id: "IwzkfMmNMpM",
@ -242,6 +249,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_-spkuonX2k", id: "_-spkuonX2k",
@ -275,6 +283,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "48pBUciAbRY", id: "48pBUciAbRY",
@ -304,5 +313,6 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
] ]

View file

@ -31,6 +31,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_UN2gwabRBI", id: "_UN2gwabRBI",
@ -60,6 +61,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aY72b4ZGPbo", id: "aY72b4ZGPbo",
@ -89,6 +91,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Cu82AvG87_g", id: "Cu82AvG87_g",
@ -118,6 +121,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "p9R94XSYjwI", id: "p9R94XSYjwI",
@ -147,6 +151,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Tlg574e9fuU", id: "Tlg574e9fuU",
@ -176,6 +181,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1L-RpSmlWp0", id: "1L-RpSmlWp0",
@ -205,6 +211,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EI28gmgBMfw", id: "EI28gmgBMfw",
@ -234,6 +241,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Z1DEwM1E7ho", id: "Z1DEwM1E7ho",
@ -267,6 +275,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hqnDi07CsJU", id: "hqnDi07CsJU",
@ -296,6 +305,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_T2tvIwOMfc", id: "_T2tvIwOMfc",
@ -325,6 +335,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "seDc-M7aSOI", id: "seDc-M7aSOI",
@ -354,6 +365,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "APJAQoSCwuA", id: "APJAQoSCwuA",
@ -383,6 +395,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "965Lv2AwODM", id: "965Lv2AwODM",
@ -412,6 +425,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Yl7NAOn0YJw", id: "Yl7NAOn0YJw",
@ -441,6 +455,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TVhoS5qhVi4", id: "TVhoS5qhVi4",
@ -470,6 +485,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dZdaP7DGze4", id: "dZdaP7DGze4",
@ -499,6 +515,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SsizZ2VZe6c", id: "SsizZ2VZe6c",
@ -528,6 +545,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xFRIddDw8bw", id: "xFRIddDw8bw",
@ -557,6 +575,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Rbhky_2qIUo", id: "Rbhky_2qIUo",
@ -586,6 +605,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ECovqS_ItUo", id: "ECovqS_ItUo",
@ -615,6 +635,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uxP0y-m6ysA", id: "uxP0y-m6ysA",
@ -644,6 +665,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "simC880SUGk", id: "simC880SUGk",
@ -673,6 +695,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dGLVJ35_gnA", id: "dGLVJ35_gnA",
@ -702,6 +725,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vY6UiUDPuMk", id: "vY6UiUDPuMk",
@ -731,6 +755,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QMQw_waEPi0", id: "QMQw_waEPi0",
@ -760,6 +785,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Sc2-3BK2mzM", id: "Sc2-3BK2mzM",
@ -793,6 +819,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bprHBlahnmM", id: "bprHBlahnmM",
@ -817,6 +844,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FMhHc5x2DzE", id: "FMhHc5x2DzE",
@ -846,6 +874,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nOjbJdw2dPs", id: "nOjbJdw2dPs",
@ -875,6 +904,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1G1zcTV5yX4", id: "1G1zcTV5yX4",
@ -904,6 +934,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BcbKoY7XpJE", id: "BcbKoY7XpJE",
@ -933,6 +964,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mq6zggKZTFU", id: "mq6zggKZTFU",
@ -962,6 +994,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aQFl1xhloVo", id: "aQFl1xhloVo",
@ -991,6 +1024,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "A3IhjA2aMUg", id: "A3IhjA2aMUg",
@ -1024,6 +1058,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cxIOWM0xLc4", id: "cxIOWM0xLc4",
@ -1053,6 +1088,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "IFKAgKgVaSI", id: "IFKAgKgVaSI",
@ -1082,6 +1118,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "iGUN99hW3nU", id: "iGUN99hW3nU",
@ -1111,6 +1148,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_alKEACsIds", id: "_alKEACsIds",
@ -1140,6 +1178,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WGNJIF7OoAc", id: "WGNJIF7OoAc",
@ -1169,6 +1208,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "a_TotMZ5hxc", id: "a_TotMZ5hxc",
@ -1202,6 +1242,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0eoeyKkWBRs", id: "0eoeyKkWBRs",
@ -1231,6 +1272,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DU4NtqyTnuM", id: "DU4NtqyTnuM",
@ -1260,6 +1302,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kLbn61Z4LDI", id: "kLbn61Z4LDI",
@ -1289,6 +1332,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vMFNI5lOLwU", id: "vMFNI5lOLwU",
@ -1326,6 +1370,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AZoZbtI67Yk", id: "AZoZbtI67Yk",
@ -1355,6 +1400,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ah4Dn3VAnMk", id: "Ah4Dn3VAnMk",
@ -1384,6 +1430,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "sLklEvxhmAQ", id: "sLklEvxhmAQ",
@ -1413,6 +1460,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2Lbp1P4pP6c", id: "2Lbp1P4pP6c",
@ -1442,6 +1490,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2TYIa09PXyo", id: "2TYIa09PXyo",
@ -1471,6 +1520,7 @@ expression: map_res.c
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Hdy7l8fkREo", id: "Hdy7l8fkREo",
@ -1500,6 +1550,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "A-sjPe3xvqY", id: "A-sjPe3xvqY",
@ -1533,6 +1584,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jFVX_v2yAas", id: "jFVX_v2yAas",
@ -1562,6 +1614,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YDfL2Ns8wz4", id: "YDfL2Ns8wz4",
@ -1591,6 +1644,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "du4hVdxqyr8", id: "du4hVdxqyr8",
@ -1620,6 +1674,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "G5vlW0PZ878", id: "G5vlW0PZ878",
@ -1649,6 +1704,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Gtg2TSR19Mg", id: "Gtg2TSR19Mg",
@ -1678,6 +1734,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vJ3wwezOV_8", id: "vJ3wwezOV_8",
@ -1707,6 +1764,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "76q5EiRyYks", id: "76q5EiRyYks",
@ -1736,6 +1794,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nEjntI9GMVM", id: "nEjntI9GMVM",
@ -1765,6 +1824,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Gtct_ipIQmo", id: "Gtct_ipIQmo",
@ -1794,6 +1854,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aw4kqTyZshk", id: "aw4kqTyZshk",
@ -1823,6 +1884,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xjoCNfK3vxo", id: "xjoCNfK3vxo",
@ -1852,6 +1914,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DN1gYO3bu-k", id: "DN1gYO3bu-k",
@ -1876,6 +1939,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "X_cqTeG7v98", id: "X_cqTeG7v98",
@ -1905,6 +1969,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "b_B4ebhKvQ4", id: "b_B4ebhKvQ4",
@ -1934,6 +1999,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VQp1QmwOzxw", id: "VQp1QmwOzxw",
@ -1963,6 +2029,7 @@ expression: map_res.c
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "suAR1PYFNYA", id: "suAR1PYFNYA",
@ -1992,6 +2059,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "No3Cr6ph-9U", id: "No3Cr6ph-9U",
@ -2021,6 +2089,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ORJEgiVY08U", id: "ORJEgiVY08U",
@ -2050,6 +2119,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2px4-y1Y0PI", id: "2px4-y1Y0PI",
@ -2079,6 +2149,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kchzKOizhGg", id: "kchzKOizhGg",
@ -2108,6 +2179,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "V6eAGSz4JI8", id: "V6eAGSz4JI8",
@ -2137,6 +2209,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1A5hWzS00Nc", id: "1A5hWzS00Nc",
@ -2166,6 +2239,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bzsSkarE4zw", id: "bzsSkarE4zw",
@ -2199,6 +2273,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "59HJZIMVxAg", id: "59HJZIMVxAg",
@ -2228,6 +2303,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8XQYz7JKjWI", id: "8XQYz7JKjWI",
@ -2257,6 +2333,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5FkJkpTWSWk", id: "5FkJkpTWSWk",
@ -2294,6 +2371,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1m51ncAU4uA", id: "1m51ncAU4uA",
@ -2327,6 +2405,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ycff6mFkoPY", id: "Ycff6mFkoPY",
@ -2356,6 +2435,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g0ghPuWqYR0", id: "g0ghPuWqYR0",
@ -2385,6 +2465,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1YiTQJcKajE", id: "1YiTQJcKajE",
@ -2414,6 +2495,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TuyisGsNr4g", id: "TuyisGsNr4g",
@ -2443,6 +2525,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ClU3aqamHGQ", id: "ClU3aqamHGQ",
@ -2472,6 +2555,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bYyB3FzPRfg", id: "bYyB3FzPRfg",
@ -2505,6 +2589,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "I5eu4XMWZR8", id: "I5eu4XMWZR8",
@ -2534,6 +2619,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ziNtA-mcXTY", id: "ziNtA-mcXTY",
@ -2563,6 +2649,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CDEikOST7ZQ", id: "CDEikOST7ZQ",
@ -2596,6 +2683,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YQzvJSR5jy8", id: "YQzvJSR5jy8",
@ -2625,6 +2713,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lPaplIqUXJc", id: "lPaplIqUXJc",
@ -2654,6 +2743,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "78Y0SxVVxP4", id: "78Y0SxVVxP4",
@ -2683,6 +2773,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2e-xqMWT9GY", id: "2e-xqMWT9GY",
@ -2712,6 +2803,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "81RRIPE404o", id: "81RRIPE404o",
@ -2741,6 +2833,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uxR8VhGG9Pc", id: "uxR8VhGG9Pc",
@ -2770,6 +2863,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JSNwR0MzGZQ", id: "JSNwR0MzGZQ",
@ -2799,6 +2893,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DS8dvzDXpjQ", id: "DS8dvzDXpjQ",
@ -2828,6 +2923,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "j10zAWP5KsM", id: "j10zAWP5KsM",
@ -2857,6 +2953,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ugFKFWhsoZA", id: "ugFKFWhsoZA",
@ -2886,6 +2983,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xXO1h6Kthcw", id: "xXO1h6Kthcw",
@ -2915,6 +3013,7 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VOUqmbeilXA", id: "VOUqmbeilXA",
@ -2944,5 +3043,6 @@ expression: map_res.c
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
] ]

View file

@ -43,6 +43,7 @@ MusicAlbum(
album_type: single, album_type: single,
year: Some(2020), year: Some(2020),
by_va: false, by_va: false,
track_count: 1,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "XX0epju-YvY", id: "XX0epju-YvY",
@ -68,6 +69,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [], variants: [],

View file

@ -0,0 +1,156 @@
---
source: src/client/music_playlist.rs
expression: map_res.c
---
MusicAlbum(
id: "MPREb_u1I69lSAe5v",
playlist_id: Some("OLAK5uy_lGP_zv0vJDUlecQDzugUJmjcF7pvyVNyY"),
name: "Waldbrand",
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/IYxE8yTIpFUu0OayA5SaxFEn6zQ7T21hpkvI8CODY9NEH1XIhyoUhGohkZuaK-xSu22BC4wjp6srNjIW=w60-h60-l90-rj",
width: 60,
height: 60,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/IYxE8yTIpFUu0OayA5SaxFEn6zQ7T21hpkvI8CODY9NEH1XIhyoUhGohkZuaK-xSu22BC4wjp6srNjIW=w120-h120-l90-rj",
width: 120,
height: 120,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/IYxE8yTIpFUu0OayA5SaxFEn6zQ7T21hpkvI8CODY9NEH1XIhyoUhGohkZuaK-xSu22BC4wjp6srNjIW=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/IYxE8yTIpFUu0OayA5SaxFEn6zQ7T21hpkvI8CODY9NEH1XIhyoUhGohkZuaK-xSu22BC4wjp6srNjIW=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
description: None,
album_type: ep,
year: Some(2016),
by_va: false,
track_count: 5,
tracks: [
TrackItem(
id: "aGd3VKSOTxY",
name: "Ich wache auf",
duration: Some(222),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: Some(208000),
track_type: track,
track_nr: Some(1),
by_va: false,
unavailable: false,
),
TrackItem(
id: "lhPOMUjV4rE",
name: "Waldbrand",
duration: Some(209),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: Some(6000000),
track_type: video,
track_nr: Some(2),
by_va: false,
unavailable: false,
),
TrackItem(
id: "Bu26uFtpt58",
name: "Verlernt",
duration: Some(224),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: Some(418000),
track_type: track,
track_nr: Some(3),
by_va: false,
unavailable: false,
),
TrackItem(
id: "RgwNqqiVqdY",
name: "In Farbe",
duration: Some(222),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: Some(127000),
track_type: track,
track_nr: Some(4),
by_va: false,
unavailable: false,
),
TrackItem(
id: "2TuOh30XbCI",
name: "Stadt im Hinterland",
duration: Some(198),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "Madeline Juno",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: Some(79000),
track_type: track,
track_nr: Some(5),
by_va: false,
unavailable: false,
),
],
variants: [],
)

View file

@ -43,6 +43,7 @@ MusicAlbum(
album_type: album, album_type: album,
year: Some(2015), year: Some(2015),
by_va: false, by_va: false,
track_count: 11,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "YQHsXMglC9A", id: "YQHsXMglC9A",
@ -64,6 +65,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fk4BbF7B29w", id: "fk4BbF7B29w",
@ -85,6 +87,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(2), track_nr: Some(2),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "z7NEG3SGZ_g", id: "z7NEG3SGZ_g",
@ -106,6 +109,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(3), track_nr: Some(3),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "a1IuJLebHgM", id: "a1IuJLebHgM",
@ -127,6 +131,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(4), track_nr: Some(4),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-fsCc7Be1H0", id: "-fsCc7Be1H0",
@ -148,6 +153,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(5), track_nr: Some(5),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "l8djdhhFuxo", id: "l8djdhhFuxo",
@ -169,6 +175,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(6), track_nr: Some(6),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Qiu59lZShCo", id: "Qiu59lZShCo",
@ -190,6 +197,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(7), track_nr: Some(7),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-hzFTJDJGkQ", id: "-hzFTJDJGkQ",
@ -211,6 +219,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(8), track_nr: Some(8),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Db9ciJPIaEU", id: "Db9ciJPIaEU",
@ -232,6 +241,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(9), track_nr: Some(9),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jb5g4UFHmfQ", id: "jb5g4UFHmfQ",
@ -253,6 +263,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(10), track_nr: Some(10),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1kZsaRkVEUY", id: "1kZsaRkVEUY",
@ -274,6 +285,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(11), track_nr: Some(11),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [], variants: [],

View file

@ -39,6 +39,7 @@ MusicAlbum(
album_type: album, album_type: album,
year: Some(2016), year: Some(2016),
by_va: false, by_va: false,
track_count: 18,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "g0iRiJ_ck48", id: "g0iRiJ_ck48",
@ -60,6 +61,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rREEBXp0y9s", id: "rREEBXp0y9s",
@ -81,6 +83,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(2), track_nr: Some(2),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zvU5Y8Q19hU", id: "zvU5Y8Q19hU",
@ -102,6 +105,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(3), track_nr: Some(3),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ARKLrzzTQA0", id: "ARKLrzzTQA0",
@ -123,6 +127,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(4), track_nr: Some(4),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tstLgN8A_Ng", id: "tstLgN8A_Ng",
@ -144,6 +149,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(5), track_nr: Some(5),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "k2DjgQOY3Ts", id: "k2DjgQOY3Ts",
@ -165,6 +171,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(6), track_nr: Some(6),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "azHwhecxEsI", id: "azHwhecxEsI",
@ -186,6 +193,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(7), track_nr: Some(7),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_FcsdYIQ2co", id: "_FcsdYIQ2co",
@ -207,6 +215,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(8), track_nr: Some(8),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "27bOWEbshyE", id: "27bOWEbshyE",
@ -228,6 +237,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(9), track_nr: Some(9),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "riD_3oZwt8w", id: "riD_3oZwt8w",
@ -249,6 +259,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(10), track_nr: Some(10),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8GNvjF3no9s", id: "8GNvjF3no9s",
@ -270,6 +281,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(11), track_nr: Some(11),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YHMFzf1uN2U", id: "YHMFzf1uN2U",
@ -291,6 +303,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(12), track_nr: Some(12),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jvV-z5F3oAo", id: "jvV-z5F3oAo",
@ -312,6 +325,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(13), track_nr: Some(13),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "u8_9cxlrh8k", id: "u8_9cxlrh8k",
@ -333,6 +347,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(14), track_nr: Some(14),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gSvKcvM1Wk0", id: "gSvKcvM1Wk0",
@ -354,6 +369,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(15), track_nr: Some(15),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wQHgKRJ0pDQ", id: "wQHgKRJ0pDQ",
@ -375,6 +391,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(16), track_nr: Some(16),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ckz5i6-hzf0", id: "Ckz5i6-hzf0",
@ -396,6 +413,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(17), track_nr: Some(17),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "y5zuUgyFqrc", id: "y5zuUgyFqrc",
@ -417,6 +435,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(18), track_nr: Some(18),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [ variants: [

View file

@ -43,6 +43,7 @@ MusicAlbum(
album_type: single, album_type: single,
year: Some(2020), year: Some(2020),
by_va: false, by_va: false,
track_count: 1,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "XX0epju-YvY", id: "XX0epju-YvY",
@ -68,6 +69,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [], variants: [],

View file

@ -34,6 +34,7 @@ MusicAlbum(
album_type: album, album_type: album,
year: Some(2019), year: Some(2019),
by_va: true, by_va: true,
track_count: 18,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "JWeJHN5P-E8", id: "JWeJHN5P-E8",
@ -55,6 +56,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5jd-AhBwcCQ", id: "5jd-AhBwcCQ",
@ -76,6 +78,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(2), track_nr: Some(2),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_cmORZMgv6I", id: "_cmORZMgv6I",
@ -97,6 +100,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(3), track_nr: Some(3),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "M_kVMsFaGYs", id: "M_kVMsFaGYs",
@ -118,6 +122,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(5), track_nr: Some(5),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "c8AfY6yhdkM", id: "c8AfY6yhdkM",
@ -139,6 +144,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(6), track_nr: Some(6),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DSQEKEegiH0", id: "DSQEKEegiH0",
@ -160,6 +166,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(7), track_nr: Some(7),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2TTOKQSzuQY", id: "2TTOKQSzuQY",
@ -181,6 +188,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(8), track_nr: Some(8),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "iRaX0BfME70", id: "iRaX0BfME70",
@ -202,6 +210,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(9), track_nr: Some(9),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Kn3cruxYj0c", id: "Kn3cruxYj0c",
@ -223,6 +232,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(11), track_nr: Some(11),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-P1FyntN_Uc", id: "-P1FyntN_Uc",
@ -244,6 +254,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(12), track_nr: Some(12),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "njdlNT1RRo4", id: "njdlNT1RRo4",
@ -265,6 +276,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(13), track_nr: Some(13),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Si-CXM8CHqQ", id: "Si-CXM8CHqQ",
@ -286,6 +298,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(18), track_nr: Some(18),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [], variants: [],

View file

@ -34,6 +34,7 @@ MusicAlbum(
album_type: single, album_type: single,
year: Some(2022), year: Some(2022),
by_va: true, by_va: true,
track_count: 6,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "8IqLxg0GqXc", id: "8IqLxg0GqXc",
@ -55,6 +56,7 @@ MusicAlbum(
track_type: video, track_type: video,
track_nr: Some(1), track_nr: Some(1),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9WYpLYAEub0", id: "9WYpLYAEub0",
@ -76,6 +78,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(2), track_nr: Some(2),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "R48tE237bW4", id: "R48tE237bW4",
@ -97,6 +100,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(3), track_nr: Some(3),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-UzsoR6z-vg", id: "-UzsoR6z-vg",
@ -118,6 +122,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(4), track_nr: Some(4),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kbNVyn8Ex28", id: "kbNVyn8Ex28",
@ -139,6 +144,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(5), track_nr: Some(5),
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "NJrQZUzWP5Y", id: "NJrQZUzWP5Y",
@ -160,6 +166,7 @@ MusicAlbum(
track_type: track, track_type: track,
track_nr: Some(6), track_nr: Some(6),
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
variants: [], variants: [],

View file

@ -59,6 +59,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: None, ctoken: None,

View file

@ -84,6 +84,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "P-zJCLBqZc4", id: "P-zJCLBqZc4",
@ -116,6 +117,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_mAPAtjWZGE", id: "_mAPAtjWZGE",
@ -148,6 +150,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JbXkjRqWTxc", id: "JbXkjRqWTxc",
@ -184,6 +187,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "72b8D6s_y_U", id: "72b8D6s_y_U",
@ -216,6 +220,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mHKNroJOcig", id: "mHKNroJOcig",
@ -248,6 +253,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0C1NFu4NB_4", id: "0C1NFu4NB_4",
@ -280,6 +286,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EnLWwwtO1-A", id: "EnLWwwtO1-A",
@ -316,6 +323,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cafxLTAWi-g", id: "cafxLTAWi-g",
@ -352,6 +360,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uyemSV1SpnE", id: "uyemSV1SpnE",
@ -384,6 +393,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ogc58xMpPCc", id: "ogc58xMpPCc",
@ -408,6 +418,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tsw1LgVkFjE", id: "tsw1LgVkFjE",
@ -440,6 +451,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xSB8trUFX1A", id: "xSB8trUFX1A",
@ -472,6 +484,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "yEKTrciCvvY", id: "yEKTrciCvvY",
@ -496,6 +509,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "LbHsWjX9dv4", id: "LbHsWjX9dv4",
@ -528,6 +542,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "L2apFB6EF-Y", id: "L2apFB6EF-Y",
@ -560,6 +575,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uCW2sZZofhk", id: "uCW2sZZofhk",
@ -592,6 +608,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XZ9DKiNZszM", id: "XZ9DKiNZszM",
@ -616,6 +633,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "J1AOKFRqCjg", id: "J1AOKFRqCjg",
@ -652,6 +670,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XNd6d6H1LBo", id: "XNd6d6H1LBo",
@ -676,6 +695,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SSy4VdjEJKM", id: "SSy4VdjEJKM",
@ -708,6 +728,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0am_BfODDvc", id: "0am_BfODDvc",
@ -744,6 +765,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xv3qKrCq2w8", id: "xv3qKrCq2w8",
@ -776,6 +798,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pZC82a-2eo0", id: "pZC82a-2eo0",
@ -808,6 +831,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kOmmYiigFLE", id: "kOmmYiigFLE",
@ -840,6 +864,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Jcp48M-vRJw", id: "Jcp48M-vRJw",
@ -872,6 +897,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YeSgtLJQGJs", id: "YeSgtLJQGJs",
@ -904,6 +930,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_LY6aFUVmOU", id: "_LY6aFUVmOU",
@ -940,6 +967,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SCTMdJ1cuoU", id: "SCTMdJ1cuoU",
@ -972,6 +1000,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TEOwoK-CMes", id: "TEOwoK-CMes",
@ -1004,6 +1033,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JgI6z6aQhEA", id: "JgI6z6aQhEA",
@ -1036,6 +1066,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1FxeCa6kypU", id: "1FxeCa6kypU",
@ -1072,6 +1103,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hG6YzmvbosI", id: "hG6YzmvbosI",
@ -1104,6 +1136,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "y3PKcVd7UtM", id: "y3PKcVd7UtM",
@ -1136,6 +1169,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UiCRuNo4dGg", id: "UiCRuNo4dGg",
@ -1168,6 +1202,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3uXHaVENo6E", id: "3uXHaVENo6E",
@ -1192,6 +1227,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EX2d37tT5fo", id: "EX2d37tT5fo",
@ -1224,6 +1260,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RjQxmy90hTg", id: "RjQxmy90hTg",
@ -1268,6 +1305,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "IsLFK8TkaVw", id: "IsLFK8TkaVw",
@ -1300,6 +1338,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "myRx1SRqxic", id: "myRx1SRqxic",
@ -1332,6 +1371,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BDuDCIt2eiY", id: "BDuDCIt2eiY",
@ -1368,6 +1408,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Do0lH6GDy7w", id: "Do0lH6GDy7w",
@ -1400,6 +1441,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g2oZ6FSl9TU", id: "g2oZ6FSl9TU",
@ -1432,6 +1474,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cHc3cXXIydc", id: "cHc3cXXIydc",
@ -1464,6 +1507,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ITW3C8lIQlk", id: "ITW3C8lIQlk",
@ -1496,6 +1540,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rKGRuQBnatM", id: "rKGRuQBnatM",
@ -1528,6 +1573,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JstDN42iDDo", id: "JstDN42iDDo",
@ -1564,6 +1610,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "POcbY0NTG9w", id: "POcbY0NTG9w",
@ -1596,6 +1643,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Jf3JOkPsogI", id: "Jf3JOkPsogI",
@ -1632,6 +1680,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lKLGceNzFAM", id: "lKLGceNzFAM",
@ -1664,6 +1713,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XNupKC5A6jc", id: "XNupKC5A6jc",
@ -1696,6 +1746,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BDWxBtjUyWQ", id: "BDWxBtjUyWQ",
@ -1728,6 +1779,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7LZIEUxH9Ro", id: "7LZIEUxH9Ro",
@ -1760,6 +1812,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5K9y2WGUl0E", id: "5K9y2WGUl0E",
@ -1792,6 +1845,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UzuQCBPpZ7U", id: "UzuQCBPpZ7U",
@ -1828,6 +1882,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SU20Ah4PE48", id: "SU20Ah4PE48",
@ -1860,6 +1915,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3RI2LsrZ9OE", id: "3RI2LsrZ9OE",
@ -1892,6 +1948,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2KoWN3sAFms", id: "2KoWN3sAFms",
@ -1924,6 +1981,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EcHhTnHOzAk", id: "EcHhTnHOzAk",
@ -1956,6 +2014,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "NjjMprtE004", id: "NjjMprtE004",
@ -1988,6 +2047,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gk5sKJ4PgPU", id: "gk5sKJ4PgPU",
@ -2020,6 +2080,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "K81Cfizqe9A", id: "K81Cfizqe9A",
@ -2052,6 +2113,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bM7QN9S0Dno", id: "bM7QN9S0Dno",
@ -2084,6 +2146,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "07O7i2BzqUM", id: "07O7i2BzqUM",
@ -2116,6 +2179,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "m2mJGmMtBfA", id: "m2mJGmMtBfA",
@ -2148,6 +2212,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0gTcGawN9xk", id: "0gTcGawN9xk",
@ -2180,6 +2245,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_tbHFWpYFbA", id: "_tbHFWpYFbA",
@ -2212,6 +2278,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "X2rGbIe14Ys", id: "X2rGbIe14Ys",
@ -2244,6 +2311,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "HIVVqNy5w_g", id: "HIVVqNy5w_g",
@ -2280,6 +2348,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cJH0qBxeBmI", id: "cJH0qBxeBmI",
@ -2304,6 +2373,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "a0C_z75ES4A", id: "a0C_z75ES4A",
@ -2336,6 +2406,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jJQAZKK5_5I", id: "jJQAZKK5_5I",
@ -2368,6 +2439,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FcBaTjGk5Cg", id: "FcBaTjGk5Cg",
@ -2400,6 +2472,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vwNNfKpGw00", id: "vwNNfKpGw00",
@ -2432,6 +2505,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UKwFZI9zHlY", id: "UKwFZI9zHlY",
@ -2464,6 +2538,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "x62rX6BYeYE", id: "x62rX6BYeYE",
@ -2496,6 +2571,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9BXn7ZNc35Q", id: "9BXn7ZNc35Q",
@ -2532,6 +2608,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QKYN0pLq1ew", id: "QKYN0pLq1ew",
@ -2564,6 +2641,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "P5Aq3oxynt4", id: "P5Aq3oxynt4",
@ -2596,6 +2674,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tYbZqVBulkU", id: "tYbZqVBulkU",
@ -2628,6 +2707,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KUpIwlt3TAA", id: "KUpIwlt3TAA",
@ -2660,6 +2740,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nlkNJ4oavoQ", id: "nlkNJ4oavoQ",
@ -2692,6 +2773,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pduHLli6NnA", id: "pduHLli6NnA",
@ -2716,6 +2798,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rbNpTesNEuw", id: "rbNpTesNEuw",
@ -2748,6 +2831,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ecMLL1XKbQA", id: "ecMLL1XKbQA",
@ -2780,6 +2864,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OvfD_geCvkI", id: "OvfD_geCvkI",
@ -2812,6 +2897,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Qg9ea0wi_18", id: "Qg9ea0wi_18",
@ -2844,6 +2930,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "z5bVgD6KjQU", id: "z5bVgD6KjQU",
@ -2880,6 +2967,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UqiemFNeprQ", id: "UqiemFNeprQ",
@ -2912,6 +3000,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1yAcDPQ7bPs", id: "1yAcDPQ7bPs",
@ -2936,6 +3025,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xbHdNkV1Bgg", id: "xbHdNkV1Bgg",
@ -2972,6 +3062,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AjGbzsAH2dI", id: "AjGbzsAH2dI",
@ -3008,6 +3099,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "29OvRKJlOX4", id: "29OvRKJlOX4",
@ -3040,6 +3132,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JVUypCxmfQA", id: "JVUypCxmfQA",
@ -3072,6 +3165,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KWIfPu8860w", id: "KWIfPu8860w",
@ -3104,6 +3198,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "x1DGqCmCeaE", id: "x1DGqCmCeaE",
@ -3136,6 +3231,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Of5EmGLKEn4", id: "Of5EmGLKEn4",
@ -3160,6 +3256,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "T9_p5vicleo", id: "T9_p5vicleo",
@ -3192,6 +3289,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "R_X1K3arztQ", id: "R_X1K3arztQ",
@ -3224,6 +3322,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VTFALCPPUN4", id: "VTFALCPPUN4",
@ -3256,6 +3355,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("4qmFsgJbEi1WTFJEQ0xBSzV1eV9rYjdFQmk2eTNHcnRKcmk0X1pINTZNczc4NkRGRWltYk0aKmVoVlFWRHBGWjNSWFZrVmFRbFJGVGxGVlJsWlBUa0dTQVFNSXVnUSUzRA%3D%3D"), ctoken: Some("4qmFsgJbEi1WTFJEQ0xBSzV1eV9rYjdFQmk2eTNHcnRKcmk0X1pINTZNczc4NkRGRWltYk0aKmVoVlFWRHBGWjNSWFZrVmFRbFJGVGxGVlJsWlBUa0dTQVFNSXVnUSUzRA%3D%3D"),

View file

@ -59,6 +59,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RPGLMuxkLCs", id: "RPGLMuxkLCs",
@ -83,6 +84,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "z-ALpnnQLrk", id: "z-ALpnnQLrk",
@ -107,6 +109,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "_rrbTTv8zcQ", id: "_rrbTTv8zcQ",
@ -131,6 +134,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "JE16OKTawLw", id: "JE16OKTawLw",
@ -155,6 +159,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RQNY0Wzm7DQ", id: "RQNY0Wzm7DQ",
@ -179,6 +184,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "uhy24PKBkd0", id: "uhy24PKBkd0",
@ -203,6 +209,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "OL1hQadBHfs", id: "OL1hQadBHfs",
@ -227,6 +234,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "Zge_SUfk0r8", id: "Zge_SUfk0r8",
@ -251,6 +259,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "yFGIeU_IDE4", id: "yFGIeU_IDE4",
@ -275,6 +284,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "P6MVqfQzPIg", id: "P6MVqfQzPIg",
@ -299,6 +309,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "9n0pLDn8Z_I", id: "9n0pLDn8Z_I",
@ -323,6 +334,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "oXbx2YtIkeQ", id: "oXbx2YtIkeQ",
@ -347,6 +359,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "pfBBTTwxo8Q", id: "pfBBTTwxo8Q",
@ -371,6 +384,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "WxtRqzxSAh0", id: "WxtRqzxSAh0",
@ -395,6 +409,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "ianUckvxtLw", id: "ianUckvxtLw",
@ -419,6 +434,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "eb2Ghj1g1ic", id: "eb2Ghj1g1ic",
@ -443,6 +459,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "8TpEsyVtCog", id: "8TpEsyVtCog",
@ -467,6 +484,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "KD_WAei4LMg", id: "KD_WAei4LMg",
@ -491,6 +509,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "qfpOCrtweKk", id: "qfpOCrtweKk",
@ -515,6 +534,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "6gv3nrOA_bQ", id: "6gv3nrOA_bQ",
@ -539,6 +559,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "waaic6UnkU8", id: "waaic6UnkU8",
@ -563,6 +584,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "lSy4MLC_uV4", id: "lSy4MLC_uV4",
@ -587,6 +609,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "BuN8-U_quok", id: "BuN8-U_quok",
@ -611,6 +634,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "g_UTG10nzaQ", id: "g_UTG10nzaQ",
@ -635,6 +659,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "kNykFWaDbGw", id: "kNykFWaDbGw",
@ -659,6 +684,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "gJF7vxCYTgY", id: "gJF7vxCYTgY",
@ -683,6 +709,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "CodZMQ_Anc0", id: "CodZMQ_Anc0",
@ -707,6 +734,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "oKHMTKJdZ_M", id: "oKHMTKJdZ_M",
@ -731,6 +759,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "--O_Eyok_eE", id: "--O_Eyok_eE",
@ -755,6 +784,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "2bT3ljKMSo8", id: "2bT3ljKMSo8",
@ -779,6 +809,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "YRAX_slrbsI", id: "YRAX_slrbsI",
@ -803,6 +834,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "aRRbCEwUSuw", id: "aRRbCEwUSuw",
@ -827,6 +859,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "5sV8SzTbJS8", id: "5sV8SzTbJS8",
@ -851,6 +884,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "ZxxZlU2o1TE", id: "ZxxZlU2o1TE",
@ -875,6 +909,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "gIjo5at4AxE", id: "gIjo5at4AxE",
@ -899,6 +934,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "NSGk7-kyeEU", id: "NSGk7-kyeEU",
@ -923,6 +959,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "cgJtZ7Otc4Y", id: "cgJtZ7Otc4Y",
@ -947,6 +984,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "l5LQu3Q0nWY", id: "l5LQu3Q0nWY",
@ -971,6 +1009,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "YX4Z3ZlWUFc", id: "YX4Z3ZlWUFc",
@ -995,6 +1034,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "LoyvqR41lKw", id: "LoyvqR41lKw",
@ -1019,6 +1059,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "HbQtMZbtx_Q", id: "HbQtMZbtx_Q",
@ -1043,6 +1084,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "0DHRbP9ecgw", id: "0DHRbP9ecgw",
@ -1067,6 +1109,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "rFOFkvk-xus", id: "rFOFkvk-xus",
@ -1091,6 +1134,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "P8zxnSihJ_8", id: "P8zxnSihJ_8",
@ -1115,6 +1159,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RWgeHl9XkCY", id: "RWgeHl9XkCY",
@ -1139,6 +1184,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "I1n539enNNY", id: "I1n539enNNY",
@ -1163,6 +1209,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "70VKekyZz5g", id: "70VKekyZz5g",
@ -1187,6 +1234,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "2OWJ1bwFu6Y", id: "2OWJ1bwFu6Y",
@ -1211,6 +1259,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "zLiSA2i-niw", id: "zLiSA2i-niw",
@ -1235,6 +1284,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "wyXlw7nMpko", id: "wyXlw7nMpko",
@ -1259,6 +1309,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "NrU4fhzvFpA", id: "NrU4fhzvFpA",
@ -1283,6 +1334,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "1xhKegaA1hQ", id: "1xhKegaA1hQ",
@ -1307,6 +1359,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "9F4lZ8psBtg", id: "9F4lZ8psBtg",
@ -1331,6 +1384,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "G3uUtejX9to", id: "G3uUtejX9to",
@ -1355,6 +1409,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "-0Xn5pViCss", id: "-0Xn5pViCss",
@ -1379,6 +1434,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "a7u71Fco99I", id: "a7u71Fco99I",
@ -1403,6 +1459,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "H6uUbvcgKdk", id: "H6uUbvcgKdk",
@ -1427,6 +1484,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "tPRTCauHtkw", id: "tPRTCauHtkw",
@ -1451,6 +1509,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "pMKAQExcarM", id: "pMKAQExcarM",
@ -1475,6 +1534,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "7E-z-7KCdBI", id: "7E-z-7KCdBI",
@ -1499,6 +1559,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "EPtbC0ZVddo", id: "EPtbC0ZVddo",
@ -1523,6 +1584,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "TpPHng0eGJs", id: "TpPHng0eGJs",
@ -1547,6 +1609,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "rt2QFQwJYcs", id: "rt2QFQwJYcs",
@ -1571,6 +1634,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "WPyfaztFDQ4", id: "WPyfaztFDQ4",
@ -1595,6 +1659,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "5lmumP0DaUw", id: "5lmumP0DaUw",
@ -1619,6 +1684,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
], ],
ctoken: None, ctoken: None,

View file

@ -59,6 +59,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8rRj5ZXRNko", id: "8rRj5ZXRNko",
@ -83,6 +84,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lHZtcC67yrY", id: "lHZtcC67yrY",
@ -107,6 +109,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TSkVVVBS9k8", id: "TSkVVVBS9k8",
@ -131,6 +134,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lc-cnCRhE7c", id: "lc-cnCRhE7c",
@ -155,6 +159,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3ryohiCVq3M", id: "3ryohiCVq3M",
@ -179,6 +184,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BNHamTwxJ6Q", id: "BNHamTwxJ6Q",
@ -207,6 +213,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5mqelmYUcI0", id: "5mqelmYUcI0",
@ -231,6 +238,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "k9EYjn5f_nE", id: "k9EYjn5f_nE",
@ -255,6 +263,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fkMg_X9lHMc", id: "fkMg_X9lHMc",
@ -279,6 +288,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4wOoLLDXbDY", id: "4wOoLLDXbDY",
@ -303,6 +313,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Z_mf9aCHag8", id: "Z_mf9aCHag8",
@ -327,6 +338,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cZ58odQo87A", id: "cZ58odQo87A",
@ -351,6 +363,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1il3RFk5Okw", id: "1il3RFk5Okw",
@ -375,6 +388,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8WQMBv2deYQ", id: "8WQMBv2deYQ",
@ -399,6 +413,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vGrfFzagzHs", id: "vGrfFzagzHs",
@ -423,6 +438,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1gDbpWC_9pE", id: "1gDbpWC_9pE",
@ -447,6 +463,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "p-AWcCCbBHw", id: "p-AWcCCbBHw",
@ -471,6 +488,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RPN88D_HjMU", id: "RPN88D_HjMU",
@ -499,6 +517,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5PST7Ld4wWU", id: "5PST7Ld4wWU",
@ -523,6 +542,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "opoDBF_b-fg", id: "opoDBF_b-fg",
@ -547,6 +567,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AMT9IOyXmBM", id: "AMT9IOyXmBM",
@ -571,6 +592,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VP5B1UmgHfc", id: "VP5B1UmgHfc",
@ -595,6 +617,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vcuQpbs0yT0", id: "vcuQpbs0yT0",
@ -619,6 +642,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "LeMLVEJLruQ", id: "LeMLVEJLruQ",
@ -643,6 +667,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "MtDPKJSsBgc", id: "MtDPKJSsBgc",
@ -667,6 +692,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4tDpYxNYqPg", id: "4tDpYxNYqPg",
@ -691,6 +717,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EkWjaoH7k6w", id: "EkWjaoH7k6w",
@ -715,6 +742,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tERRFWuYG48", id: "tERRFWuYG48",
@ -739,6 +767,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wCcJuN47UcY", id: "wCcJuN47UcY",
@ -763,6 +792,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qdtLCfEcPL4", id: "qdtLCfEcPL4",
@ -787,6 +817,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wjXUBG15eZ8", id: "wjXUBG15eZ8",
@ -811,6 +842,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "HBjDZMJUduo", id: "HBjDZMJUduo",
@ -835,6 +867,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xkXQQ0IAbk0", id: "xkXQQ0IAbk0",
@ -859,6 +892,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DraA3PUuoQc", id: "DraA3PUuoQc",
@ -883,6 +917,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wMIGQp4YhuU", id: "wMIGQp4YhuU",
@ -907,6 +942,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "38lrK74voaI", id: "38lrK74voaI",
@ -931,6 +967,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2qW9rOSFF1M", id: "2qW9rOSFF1M",
@ -959,6 +996,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tMILH6UEfPA", id: "tMILH6UEfPA",
@ -983,6 +1021,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "izHB2EdMngg", id: "izHB2EdMngg",
@ -1007,6 +1046,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "haECT-SerHk", id: "haECT-SerHk",
@ -1031,6 +1071,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cVikZ8Oe_XA", id: "cVikZ8Oe_XA",
@ -1055,6 +1096,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "drFsXLChrWc", id: "drFsXLChrWc",
@ -1079,6 +1121,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1EMFt7m_8yE", id: "1EMFt7m_8yE",
@ -1103,6 +1146,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_yWU0lFghxU", id: "_yWU0lFghxU",
@ -1127,6 +1171,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XlD-LO3ogFM", id: "XlD-LO3ogFM",
@ -1151,6 +1196,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nAzjWqNfgvc", id: "nAzjWqNfgvc",
@ -1179,6 +1225,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PySC3RGhZJU", id: "PySC3RGhZJU",
@ -1203,6 +1250,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "G-iwLoyH6ZE", id: "G-iwLoyH6ZE",
@ -1227,6 +1275,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fgCOUO-s8nY", id: "fgCOUO-s8nY",
@ -1251,6 +1300,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "m-Ik3yy728Y", id: "m-Ik3yy728Y",
@ -1275,6 +1325,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "U0_UYW5Y4cM", id: "U0_UYW5Y4cM",
@ -1299,6 +1350,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rsrDYTEicq8", id: "rsrDYTEicq8",
@ -1323,6 +1375,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2aU4wRgl_0E", id: "2aU4wRgl_0E",
@ -1347,6 +1400,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FzcJxJAxFtw", id: "FzcJxJAxFtw",
@ -1375,6 +1429,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2hyibXdOp5w", id: "2hyibXdOp5w",
@ -1399,6 +1454,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YaKG5cUVB30", id: "YaKG5cUVB30",
@ -1423,6 +1479,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ahwc-ouFeTQ", id: "Ahwc-ouFeTQ",
@ -1447,6 +1504,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SoImFhORKpg", id: "SoImFhORKpg",
@ -1471,6 +1529,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jP4-XrbGt3M", id: "jP4-XrbGt3M",
@ -1495,6 +1554,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Yy2RsG4lnm4", id: "Yy2RsG4lnm4",
@ -1519,6 +1579,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "388e_8mu1t4", id: "388e_8mu1t4",
@ -1543,6 +1604,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dHHtPi-j7dQ", id: "dHHtPi-j7dQ",
@ -1567,6 +1629,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "d8ERTCVXIUE", id: "d8ERTCVXIUE",
@ -1591,6 +1654,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vQXn3EzzYY4", id: "vQXn3EzzYY4",
@ -1615,6 +1679,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zA-BTpC-yvI", id: "zA-BTpC-yvI",
@ -1639,6 +1704,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rnzIN9H_G10", id: "rnzIN9H_G10",
@ -1663,6 +1729,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fcBbT1GTxqM", id: "fcBbT1GTxqM",
@ -1687,6 +1754,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "wCDsm_dt1cI", id: "wCDsm_dt1cI",
@ -1711,6 +1779,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4j3AOJV1J8I", id: "4j3AOJV1J8I",
@ -1735,6 +1804,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RtuW08ZIgvg", id: "RtuW08ZIgvg",
@ -1759,6 +1829,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cbTXqKBIQ40", id: "cbTXqKBIQ40",
@ -1783,6 +1854,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "oSd0Lph4luY", id: "oSd0Lph4luY",
@ -1807,6 +1879,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "oq0rrYrufYU", id: "oq0rrYrufYU",
@ -1831,6 +1904,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0-P_YkS0z8s", id: "0-P_YkS0z8s",
@ -1855,6 +1929,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4BAKb2p450Q", id: "4BAKb2p450Q",
@ -1879,6 +1954,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "yqObMM_QzVQ", id: "yqObMM_QzVQ",
@ -1903,6 +1979,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dlvStoOyEzE", id: "dlvStoOyEzE",
@ -1927,6 +2004,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VNttGAaek2U", id: "VNttGAaek2U",
@ -1951,6 +2029,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TxZMfufRJfo", id: "TxZMfufRJfo",
@ -1975,6 +2054,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "6agT2asF4as", id: "6agT2asF4as",
@ -1999,6 +2079,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EcW0n83La5A", id: "EcW0n83La5A",
@ -2023,6 +2104,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_b61hg8UlZM", id: "_b61hg8UlZM",
@ -2047,6 +2129,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kDMFranvFuQ", id: "kDMFranvFuQ",
@ -2071,6 +2154,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1apku0pVDeE", id: "1apku0pVDeE",
@ -2095,6 +2179,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g6JYzOjglBs", id: "g6JYzOjglBs",
@ -2119,6 +2204,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "GYK-NfOo7b4", id: "GYK-NfOo7b4",
@ -2143,6 +2229,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "omUuR45iU0g", id: "omUuR45iU0g",
@ -2167,6 +2254,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "w7BE3inS-NM", id: "w7BE3inS-NM",
@ -2191,6 +2279,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FM-5BPMnhm0", id: "FM-5BPMnhm0",
@ -2215,6 +2304,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "MnNZNfixTOw", id: "MnNZNfixTOw",
@ -2239,6 +2329,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qe80EeU8cT8", id: "qe80EeU8cT8",
@ -2263,6 +2354,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-s2-6KYgqpQ", id: "-s2-6KYgqpQ",
@ -2287,6 +2379,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RSlp874hESE", id: "RSlp874hESE",
@ -2315,6 +2408,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "oTI3tRQ_-3k", id: "oTI3tRQ_-3k",
@ -2339,6 +2433,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_okA84gaEJw", id: "_okA84gaEJw",
@ -2363,6 +2458,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pLHnnJRaP7Q", id: "pLHnnJRaP7Q",
@ -2387,6 +2483,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "H2hGrsExuyc", id: "H2hGrsExuyc",
@ -2411,6 +2508,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RsZvjqG2lec", id: "RsZvjqG2lec",
@ -2435,6 +2533,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qYRCiQ6d35w", id: "qYRCiQ6d35w",
@ -2463,6 +2562,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("4qmFsgI-EiRWTFBMNWREeDY4MVQ0YlI3WkYxSXVXek92MW9tbFJiRTdQaUoaFmVnWlFWRHBEUjFtU0FRTUl1Z1ElM0Q%3D"), ctoken: Some("4qmFsgI-EiRWTFBMNWREeDY4MVQ0YlI3WkYxSXVXek92MW9tbFJiRTdQaUoaFmVnWlFWRHBEUjFtU0FRTUl1Z1ElM0Q%3D"),

View file

@ -59,6 +59,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RPGLMuxkLCs", id: "RPGLMuxkLCs",
@ -83,6 +84,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "z-ALpnnQLrk", id: "z-ALpnnQLrk",
@ -107,6 +109,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "_rrbTTv8zcQ", id: "_rrbTTv8zcQ",
@ -131,6 +134,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "JE16OKTawLw", id: "JE16OKTawLw",
@ -155,6 +159,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RQNY0Wzm7DQ", id: "RQNY0Wzm7DQ",
@ -179,6 +184,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "uhy24PKBkd0", id: "uhy24PKBkd0",
@ -203,6 +209,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "OL1hQadBHfs", id: "OL1hQadBHfs",
@ -227,6 +234,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "Zge_SUfk0r8", id: "Zge_SUfk0r8",
@ -251,6 +259,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "yFGIeU_IDE4", id: "yFGIeU_IDE4",
@ -275,6 +284,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "P6MVqfQzPIg", id: "P6MVqfQzPIg",
@ -299,6 +309,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "9n0pLDn8Z_I", id: "9n0pLDn8Z_I",
@ -323,6 +334,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "oXbx2YtIkeQ", id: "oXbx2YtIkeQ",
@ -347,6 +359,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "pfBBTTwxo8Q", id: "pfBBTTwxo8Q",
@ -371,6 +384,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "WxtRqzxSAh0", id: "WxtRqzxSAh0",
@ -395,6 +409,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "ianUckvxtLw", id: "ianUckvxtLw",
@ -419,6 +434,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "eb2Ghj1g1ic", id: "eb2Ghj1g1ic",
@ -443,6 +459,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "8TpEsyVtCog", id: "8TpEsyVtCog",
@ -467,6 +484,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "KD_WAei4LMg", id: "KD_WAei4LMg",
@ -491,6 +509,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "qfpOCrtweKk", id: "qfpOCrtweKk",
@ -515,6 +534,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "6gv3nrOA_bQ", id: "6gv3nrOA_bQ",
@ -539,6 +559,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "waaic6UnkU8", id: "waaic6UnkU8",
@ -563,6 +584,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "lSy4MLC_uV4", id: "lSy4MLC_uV4",
@ -587,6 +609,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "BuN8-U_quok", id: "BuN8-U_quok",
@ -611,6 +634,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "g_UTG10nzaQ", id: "g_UTG10nzaQ",
@ -635,6 +659,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "kNykFWaDbGw", id: "kNykFWaDbGw",
@ -659,6 +684,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "gJF7vxCYTgY", id: "gJF7vxCYTgY",
@ -683,6 +709,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "CodZMQ_Anc0", id: "CodZMQ_Anc0",
@ -707,6 +734,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "oKHMTKJdZ_M", id: "oKHMTKJdZ_M",
@ -731,6 +759,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "--O_Eyok_eE", id: "--O_Eyok_eE",
@ -755,6 +784,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "2bT3ljKMSo8", id: "2bT3ljKMSo8",
@ -779,6 +809,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "YRAX_slrbsI", id: "YRAX_slrbsI",
@ -803,6 +834,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "aRRbCEwUSuw", id: "aRRbCEwUSuw",
@ -827,6 +859,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "5sV8SzTbJS8", id: "5sV8SzTbJS8",
@ -851,6 +884,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "ZxxZlU2o1TE", id: "ZxxZlU2o1TE",
@ -875,6 +909,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "gIjo5at4AxE", id: "gIjo5at4AxE",
@ -899,6 +934,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "NSGk7-kyeEU", id: "NSGk7-kyeEU",
@ -923,6 +959,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "cgJtZ7Otc4Y", id: "cgJtZ7Otc4Y",
@ -947,6 +984,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "l5LQu3Q0nWY", id: "l5LQu3Q0nWY",
@ -971,6 +1009,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "YX4Z3ZlWUFc", id: "YX4Z3ZlWUFc",
@ -995,6 +1034,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "LoyvqR41lKw", id: "LoyvqR41lKw",
@ -1019,6 +1059,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "HbQtMZbtx_Q", id: "HbQtMZbtx_Q",
@ -1043,6 +1084,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "0DHRbP9ecgw", id: "0DHRbP9ecgw",
@ -1067,6 +1109,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "rFOFkvk-xus", id: "rFOFkvk-xus",
@ -1091,6 +1134,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "P8zxnSihJ_8", id: "P8zxnSihJ_8",
@ -1115,6 +1159,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "RWgeHl9XkCY", id: "RWgeHl9XkCY",
@ -1139,6 +1184,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "I1n539enNNY", id: "I1n539enNNY",
@ -1163,6 +1209,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "70VKekyZz5g", id: "70VKekyZz5g",
@ -1187,6 +1234,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "2OWJ1bwFu6Y", id: "2OWJ1bwFu6Y",
@ -1211,6 +1259,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "zLiSA2i-niw", id: "zLiSA2i-niw",
@ -1235,6 +1284,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "wyXlw7nMpko", id: "wyXlw7nMpko",
@ -1259,6 +1309,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "NrU4fhzvFpA", id: "NrU4fhzvFpA",
@ -1283,6 +1334,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "1xhKegaA1hQ", id: "1xhKegaA1hQ",
@ -1307,6 +1359,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "9F4lZ8psBtg", id: "9F4lZ8psBtg",
@ -1331,6 +1384,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "G3uUtejX9to", id: "G3uUtejX9to",
@ -1355,6 +1409,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "-0Xn5pViCss", id: "-0Xn5pViCss",
@ -1379,6 +1434,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "a7u71Fco99I", id: "a7u71Fco99I",
@ -1403,6 +1459,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "H6uUbvcgKdk", id: "H6uUbvcgKdk",
@ -1427,6 +1484,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "tPRTCauHtkw", id: "tPRTCauHtkw",
@ -1451,6 +1509,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "pMKAQExcarM", id: "pMKAQExcarM",
@ -1475,6 +1534,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "7E-z-7KCdBI", id: "7E-z-7KCdBI",
@ -1499,6 +1559,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "EPtbC0ZVddo", id: "EPtbC0ZVddo",
@ -1523,6 +1584,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "TpPHng0eGJs", id: "TpPHng0eGJs",
@ -1547,6 +1609,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "rt2QFQwJYcs", id: "rt2QFQwJYcs",
@ -1571,6 +1634,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "WPyfaztFDQ4", id: "WPyfaztFDQ4",
@ -1595,6 +1659,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "5lmumP0DaUw", id: "5lmumP0DaUw",
@ -1619,6 +1684,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
], ],
ctoken: None, ctoken: None,

View file

@ -61,6 +61,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nBZlrbrBO1I", id: "nBZlrbrBO1I",
@ -85,6 +86,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AcTDlsUej2w", id: "AcTDlsUej2w",
@ -109,6 +111,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "k6ZoE4RrcDs", id: "k6ZoE4RrcDs",
@ -133,6 +136,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2n5GKLdrTfk", id: "2n5GKLdrTfk",
@ -157,6 +161,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "psuRGfAaju4", id: "psuRGfAaju4",
@ -181,6 +186,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_JGGLJMpVks", id: "_JGGLJMpVks",
@ -205,6 +211,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1YUBbF24H44", id: "1YUBbF24H44",
@ -229,6 +236,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "E0WRQpjckYg", id: "E0WRQpjckYg",
@ -253,6 +261,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mqiH0ZSkM9I", id: "mqiH0ZSkM9I",
@ -277,6 +286,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UAWcs5H-qgQ", id: "UAWcs5H-qgQ",
@ -301,6 +311,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bqO3Y5e4Dow", id: "bqO3Y5e4Dow",
@ -325,6 +336,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ouEezpuPc3A", id: "ouEezpuPc3A",
@ -349,6 +361,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "i-qT5n_5Mys", id: "i-qT5n_5Mys",
@ -373,6 +386,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PMGY8fLwess", id: "PMGY8fLwess",
@ -397,6 +411,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2ebfSItB0oM", id: "2ebfSItB0oM",
@ -421,6 +436,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "c4BLVznuWnU", id: "c4BLVznuWnU",
@ -445,6 +461,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "c0wUKCekI34", id: "c0wUKCekI34",
@ -469,6 +486,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vNfgVjZF8_4", id: "vNfgVjZF8_4",
@ -493,6 +511,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XPpTgCho5ZA", id: "XPpTgCho5ZA",
@ -517,6 +536,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-oqAU5VxFWs", id: "-oqAU5VxFWs",
@ -541,6 +561,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CA1VHbdq5hY", id: "CA1VHbdq5hY",
@ -565,6 +586,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aNzCDt2eidg", id: "aNzCDt2eidg",
@ -589,6 +611,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "A48hOToMuRE", id: "A48hOToMuRE",
@ -613,6 +636,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qHm9MG9xw1o", id: "qHm9MG9xw1o",
@ -637,6 +661,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "74NhLkjIeMs", id: "74NhLkjIeMs",
@ -661,6 +686,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EptPhiK_q0E", id: "EptPhiK_q0E",
@ -685,6 +711,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "44u7_wQ1s0g", id: "44u7_wQ1s0g",
@ -709,6 +736,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "toOyxylnNkI", id: "toOyxylnNkI",
@ -733,6 +761,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ljXSjIph5ZM", id: "ljXSjIph5ZM",
@ -757,6 +786,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DJFMRLIe-0o", id: "DJFMRLIe-0o",
@ -785,6 +815,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "goqqohUitmw", id: "goqqohUitmw",
@ -809,6 +840,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_LwX7GCE5rI", id: "_LwX7GCE5rI",
@ -833,6 +865,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7KHPC-kEQOA", id: "7KHPC-kEQOA",
@ -861,6 +894,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "26PAgklYYvo", id: "26PAgklYYvo",
@ -885,6 +919,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bO3S8CKafbE", id: "bO3S8CKafbE",
@ -909,6 +944,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tMsbeyeTtpk", id: "tMsbeyeTtpk",
@ -933,6 +969,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fvXn3rmhdc4", id: "fvXn3rmhdc4",
@ -957,6 +994,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2p4n7JgdCsc", id: "2p4n7JgdCsc",
@ -981,6 +1019,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "HtNS1afUOnE", id: "HtNS1afUOnE",
@ -1005,6 +1044,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ufbDvPaVrzs", id: "ufbDvPaVrzs",
@ -1029,6 +1069,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "H1_icnjg6MY", id: "H1_icnjg6MY",
@ -1053,6 +1094,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7Lna4Hu4-AQ", id: "7Lna4Hu4-AQ",
@ -1081,6 +1123,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "K9qu2QMBguw", id: "K9qu2QMBguw",
@ -1113,6 +1156,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uWeqeQkjLto", id: "uWeqeQkjLto",
@ -1137,6 +1181,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "X_ZOGHUWwqE", id: "X_ZOGHUWwqE",
@ -1161,6 +1206,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mHeK0Cwr9sg", id: "mHeK0Cwr9sg",
@ -1185,6 +1231,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0Bf3CJZ4hvg", id: "0Bf3CJZ4hvg",
@ -1209,6 +1256,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7TCncxWNcPU", id: "7TCncxWNcPU",
@ -1233,6 +1281,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PxNYvk_0Onw", id: "PxNYvk_0Onw",
@ -1257,6 +1306,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WLoWBe9BRP4", id: "WLoWBe9BRP4",
@ -1281,6 +1331,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1XYLKoEETVA", id: "1XYLKoEETVA",
@ -1305,6 +1356,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ghl_vkEV3tc", id: "Ghl_vkEV3tc",
@ -1329,6 +1381,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5qHRMFQ0pLg", id: "5qHRMFQ0pLg",
@ -1353,6 +1406,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "X-vispdELDo", id: "X-vispdELDo",
@ -1377,6 +1431,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "il_L6c_fOvs", id: "il_L6c_fOvs",
@ -1401,6 +1456,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hCjcgoubkPM", id: "hCjcgoubkPM",
@ -1425,6 +1481,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nwXlRq_QyTI", id: "nwXlRq_QyTI",
@ -1449,6 +1506,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ZdsER1S3t8k", id: "ZdsER1S3t8k",
@ -1477,6 +1535,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fyrsExw_LUg", id: "fyrsExw_LUg",
@ -1501,6 +1560,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BS4t017LSoA", id: "BS4t017LSoA",
@ -1533,6 +1593,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0AYzzzBaPBI", id: "0AYzzzBaPBI",
@ -1557,6 +1618,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zM0K3LC7Aak", id: "zM0K3LC7Aak",
@ -1581,6 +1643,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1le0xDbrVj8", id: "1le0xDbrVj8",
@ -1605,6 +1668,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RdFaKz71-5M", id: "RdFaKz71-5M",
@ -1629,6 +1693,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "d6hUByfuhM4", id: "d6hUByfuhM4",
@ -1653,6 +1718,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-uxeu0MbNR0", id: "-uxeu0MbNR0",
@ -1677,6 +1743,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "35VK8yonvsc", id: "35VK8yonvsc",
@ -1701,6 +1768,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ELD3aRzbVQg", id: "ELD3aRzbVQg",
@ -1725,6 +1793,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BD7HwXv18aU", id: "BD7HwXv18aU",
@ -1749,6 +1818,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WJJLfUwIVR4", id: "WJJLfUwIVR4",
@ -1773,6 +1843,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "NjW1S0WIiJw", id: "NjW1S0WIiJw",
@ -1797,6 +1868,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-4szr0EMrgk", id: "-4szr0EMrgk",
@ -1821,6 +1893,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "88NWeOGrxys", id: "88NWeOGrxys",
@ -1853,6 +1926,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BxqtS-7GxFM", id: "BxqtS-7GxFM",
@ -1877,6 +1951,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KUKt_LbaBnM", id: "KUKt_LbaBnM",
@ -1901,6 +1976,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bhL7A8k6kU8", id: "bhL7A8k6kU8",
@ -1925,6 +2001,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mUN36hFtazE", id: "mUN36hFtazE",
@ -1949,6 +2026,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "dcBZP_pt0uY", id: "dcBZP_pt0uY",
@ -1973,6 +2051,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "m342B1Vv3tM", id: "m342B1Vv3tM",
@ -1997,6 +2076,7 @@ MusicPlaylist(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "N_5RiRBvPSk", id: "N_5RiRBvPSk",
@ -2029,6 +2109,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Q5kH0wg_sKo", id: "Q5kH0wg_sKo",
@ -2061,6 +2142,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "j9zlc5zufl8", id: "j9zlc5zufl8",
@ -2093,6 +2175,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ufxjiU7BgR4", id: "ufxjiU7BgR4",
@ -2125,6 +2208,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7OfB_8rrtug", id: "7OfB_8rrtug",
@ -2157,6 +2241,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UqmvAc81XuM", id: "UqmvAc81XuM",
@ -2189,6 +2274,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QDULTFB8gSY", id: "QDULTFB8gSY",
@ -2221,6 +2307,7 @@ MusicPlaylist(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: None, ctoken: None,

View file

@ -54,6 +54,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "aZ1hziFhj1o", id: "aZ1hziFhj1o",
@ -86,6 +87,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_l2IU1O3l6QK", id: "MPREb_l2IU1O3l6QK",
@ -154,6 +156,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "65Q7EdWnjqM", id: "65Q7EdWnjqM",
@ -186,6 +189,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "EL72UcDZLSk", id: "EL72UcDZLSk",
@ -218,6 +222,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "b1kbLwvqugk", id: "b1kbLwvqugk",
@ -242,6 +247,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "3tmd-ClpJxA", id: "3tmd-ClpJxA",
@ -266,6 +272,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "FuXNumBwDOM", id: "FuXNumBwDOM",
@ -290,6 +297,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_BiCQyyofUtj", id: "MPREb_BiCQyyofUtj",

View file

@ -29,6 +29,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "NU611fxGyPU", id: "NU611fxGyPU",
@ -53,6 +54,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "Yi2nsnpw5h0", id: "Yi2nsnpw5h0",
@ -77,6 +79,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "2Qefh0W_H88", id: "2Qefh0W_H88",
@ -101,6 +104,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "BL-aIpCLWnU", id: "BL-aIpCLWnU",
@ -133,6 +137,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "PpKu3UsHYrk", id: "PpKu3UsHYrk",
@ -165,6 +170,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "jynOfK8JB0E", id: "jynOfK8JB0E",
@ -197,6 +203,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "pgjQkcYD-rQ", id: "pgjQkcYD-rQ",
@ -221,6 +228,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "w2GXdb-pHo8", id: "w2GXdb-pHo8",
@ -245,6 +253,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "JepNreB58TA", id: "JepNreB58TA",
@ -269,6 +278,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_rR0VQ4fTxPM", id: "MPREb_rR0VQ4fTxPM",
@ -616,6 +626,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "GE0UAdxPTc0", id: "GE0UAdxPTc0",
@ -640,6 +651,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "4gi9y3sTrXE", id: "4gi9y3sTrXE",
@ -664,6 +676,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
User(UserItem( User(UserItem(
id: "UCOeTBeQwhOSvNcaZhxM1PUg", id: "UCOeTBeQwhOSvNcaZhxM1PUg",

View file

@ -67,6 +67,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "Yx-sGL0xX-U", id: "Yx-sGL0xX-U",
@ -99,6 +100,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "HzdD8kbDzZA", id: "HzdD8kbDzZA",
@ -131,6 +133,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "Zh7Un8gVFak", id: "Zh7Un8gVFak",
@ -155,6 +158,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "BMnD36Abw_0", id: "BMnD36Abw_0",
@ -179,6 +183,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_UQFAF6UM4DN", id: "MPREb_UQFAF6UM4DN",
@ -611,6 +616,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "MiVivWh7zrA", id: "MiVivWh7zrA",
@ -635,6 +641,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "7-hMhhUO8b8", id: "7-hMhhUO8b8",
@ -659,6 +666,7 @@ MusicSearchResult(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
User(UserItem( User(UserItem(
id: "UCdQrWgvHD9f-caMSn3SS-WQ", id: "UCdQrWgvHD9f-caMSn3SS-WQ",

View file

@ -37,6 +37,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "VHLPvrlclmQ", id: "VHLPvrlclmQ",
@ -69,6 +70,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "R9TPed_ohKM", id: "R9TPed_ohKM",
@ -101,6 +103,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "Ej1nxBxFSKc", id: "Ej1nxBxFSKc",
@ -125,6 +128,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "26OrUhkRa3c", id: "26OrUhkRa3c",
@ -149,6 +153,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "Idk-oFqn3kM", id: "Idk-oFqn3kM",
@ -173,6 +178,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_CYbQPbuAWrt", id: "MPREb_CYbQPbuAWrt",

View file

@ -73,6 +73,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "pt0YvfnhGgI", id: "pt0YvfnhGgI",
@ -105,6 +106,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "0yPnvetCm-U", id: "0yPnvetCm-U",
@ -137,6 +139,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "3ryohiCVq3M", id: "3ryohiCVq3M",
@ -161,6 +164,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "6Bt1KeMNqvc", id: "6Bt1KeMNqvc",
@ -185,6 +189,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Track(TrackItem( Track(TrackItem(
id: "5YQRHUItXTI", id: "5YQRHUItXTI",
@ -209,6 +214,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
Album(AlbumItem( Album(AlbumItem(
id: "MPREb_V5f8YfHKp2j", id: "MPREb_V5f8YfHKp2j",

View file

@ -75,6 +75,7 @@ MusicSearchSuggestion(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
)), )),
], ],
) )

View file

@ -37,6 +37,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cATe8Toht70", id: "cATe8Toht70",
@ -73,6 +74,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0I1UpXSYdOQ", id: "0I1UpXSYdOQ",
@ -105,6 +107,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9G2tG8V5_PY", id: "9G2tG8V5_PY",
@ -137,6 +140,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WwNKyoizf8k", id: "WwNKyoizf8k",
@ -169,6 +173,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kS1o36LXQkc", id: "kS1o36LXQkc",
@ -201,6 +206,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UQQ6L1j6mXE", id: "UQQ6L1j6mXE",
@ -233,6 +239,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9l9dCro-7l8", id: "9l9dCro-7l8",
@ -265,6 +272,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "S_PRpDtgUfI", id: "S_PRpDtgUfI",
@ -297,6 +305,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Xt_ReZc0gnw", id: "Xt_ReZc0gnw",
@ -329,6 +338,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "diN3WCxpqis", id: "diN3WCxpqis",
@ -361,6 +371,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "9q3FfH_57Rc", id: "9q3FfH_57Rc",
@ -393,6 +404,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "U29V08A9yBs", id: "U29V08A9yBs",
@ -429,6 +441,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "HHEKbGlLoEM", id: "HHEKbGlLoEM",
@ -461,6 +474,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qE_dGvQG1rU", id: "qE_dGvQG1rU",
@ -493,6 +507,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1tyPs3ccT7E", id: "1tyPs3ccT7E",
@ -529,6 +544,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "6pSmQ-MHKbg", id: "6pSmQ-MHKbg",
@ -561,6 +577,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rNsISA-kWzM", id: "rNsISA-kWzM",
@ -593,6 +610,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AdvPpJVvyEg", id: "AdvPpJVvyEg",
@ -625,6 +643,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7q7o-kjIKpo", id: "7q7o-kjIKpo",
@ -657,6 +676,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlJQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVF0Q1RDMWhTWEJEVEZkdVZZSUJDMk5CVkdVNFZHOW9kRGN3Z2dFTE1Fa3hWWEJZVTFsa1QxR0NBUXM1UnpKMFJ6aFdOVjlRV1lJQkMxZDNUa3Q1YjJsNlpqaHJnZ0VMYTFNeGJ6TTJURmhSYTJPQ0FRdFZVVkUyVERGcU5tMVlSWUlCQ3psc09XUkRjbTh0TjJ3NGdnRUxVMTlRVW5CRWRHZFZaa21DQVF0WWRGOVNaVnBqTUdkdWQ0SUJDMlJwVGpOWFEzaHdjV2x6Z2dFTE9YRXpSbVpJWHpVM1VtT0NBUXRWTWpsV01EaEJPWGxDYzRJQkMwaElSVXRpUjJ4TWIwVk5nZ0VMY1VWZlpFZDJVVWN4Y2xXQ0FRdEVXak14Y0hoNVdXaFNhNElCQ3pad1UyMVJMVTFJUzJKbmdnRUxjazV6U1ZOQkxXdFhlazJDQVF0QlpIWlFjRXBXZG5sRlo0SUJDemR4TjI4dGEycEpTM0J2GPHq0C4%3D"), ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlJQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVF0Q1RDMWhTWEJEVEZkdVZZSUJDMk5CVkdVNFZHOW9kRGN3Z2dFTE1Fa3hWWEJZVTFsa1QxR0NBUXM1UnpKMFJ6aFdOVjlRV1lJQkMxZDNUa3Q1YjJsNlpqaHJnZ0VMYTFNeGJ6TTJURmhSYTJPQ0FRdFZVVkUyVERGcU5tMVlSWUlCQ3psc09XUkRjbTh0TjJ3NGdnRUxVMTlRVW5CRWRHZFZaa21DQVF0WWRGOVNaVnBqTUdkdWQ0SUJDMlJwVGpOWFEzaHdjV2x6Z2dFTE9YRXpSbVpJWHpVM1VtT0NBUXRWTWpsV01EaEJPWGxDYzRJQkMwaElSVXRpUjJ4TWIwVk5nZ0VMY1VWZlpFZDJVVWN4Y2xXQ0FRdEVXak14Y0hoNVdXaFNhNElCQ3pad1UyMVJMVTFJUzJKbmdnRUxjazV6U1ZOQkxXdFhlazJDQVF0QlpIWlFjRXBXZG5sRlo0SUJDemR4TjI4dGEycEpTM0J2GPHq0C4%3D"),

View file

@ -41,6 +41,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OJ5ZittaTCk", id: "OJ5ZittaTCk",
@ -73,6 +74,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "H199HKaUk3g", id: "H199HKaUk3g",
@ -105,6 +107,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UlNOkZEcSjQ", id: "UlNOkZEcSjQ",
@ -137,6 +140,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "L61sF-655Zw", id: "L61sF-655Zw",
@ -169,6 +173,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "bOK90e8P3k0", id: "bOK90e8P3k0",
@ -201,6 +206,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "oRHLx2mc2zY", id: "oRHLx2mc2zY",
@ -241,6 +247,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: None, ctoken: None,

View file

@ -37,6 +37,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pt0YvfnhGgI", id: "pt0YvfnhGgI",
@ -69,6 +70,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VinJmH-uidY", id: "VinJmH-uidY",
@ -101,6 +103,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YmSmymHRnEE", id: "YmSmymHRnEE",
@ -133,6 +136,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TgfIbiHCOLo", id: "TgfIbiHCOLo",
@ -165,6 +169,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lCi6N_uq3vE", id: "lCi6N_uq3vE",
@ -197,6 +202,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QIjqe2B3RdQ", id: "QIjqe2B3RdQ",
@ -229,6 +235,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "q2pUotlXPeM", id: "q2pUotlXPeM",
@ -261,6 +268,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0yPnvetCm-U", id: "0yPnvetCm-U",
@ -293,6 +301,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EU5Vly60VGU", id: "EU5Vly60VGU",
@ -325,6 +334,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UnxQ0TI4IMs", id: "UnxQ0TI4IMs",
@ -357,6 +367,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ufpny1KxwcU", id: "ufpny1KxwcU",
@ -389,6 +400,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "duzWgZFJNwA", id: "duzWgZFJNwA",
@ -421,6 +433,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "rnXq-1n0lt0", id: "rnXq-1n0lt0",
@ -453,6 +466,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vHkqdC6-rOI", id: "vHkqdC6-rOI",
@ -485,6 +499,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "nTlceSET_b8", id: "nTlceSET_b8",
@ -517,6 +532,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "D8GhmRiIfxI", id: "D8GhmRiIfxI",
@ -549,6 +565,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "01CS-jTaY1U", id: "01CS-jTaY1U",
@ -581,6 +598,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2sKkKKKXO28", id: "2sKkKKKXO28",
@ -613,6 +631,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "czlgl6n9voM", id: "czlgl6n9voM",
@ -645,6 +664,7 @@ MusicSearchResult(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("EqcDEg5saWJsaW5nc21lbnNjaBqUA0VnV0tBUUlJQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVFzMk5EZzFVR2hQZEVoNldZSUJDM0IwTUZsMlptNW9SMmRKZ2dFTFZtbHVTbTFJTFhWcFpGbUNBUXRaYlZOdGVXMUlVbTVGUllJQkMxUm5aa2xpYVVoRFQweHZnZ0VMYkVOcE5rNWZkWEV6ZGtXQ0FRdFJTV3B4WlRKQ00xSmtVWUlCQzNFeWNGVnZkR3hZVUdWTmdnRUxNSGxRYm5abGRFTnRMVldDQVF0RlZUVldiSGsyTUZaSFZZSUJDMVZ1ZUZFd1ZFazBTVTF6Z2dFTGRXWndibmt4UzNoM1kxV0NBUXRrZFhwWFoxcEdTazUzUVlJQkMzSnVXSEV0TVc0d2JIUXdnZ0VMZGtocmNXUkROaTF5VDBtQ0FRdHVWR3hqWlZORlZGOWlPSUlCQzBRNFIyaHRVbWxKWm5oSmdnRUxNREZEVXkxcVZHRlpNVldDQVFzeWMwdHJTMHRMV0U4eU9JSUJDMk42Ykdkc05tNDVkbTlOGPHq0C4%3D"), ctoken: Some("EqcDEg5saWJsaW5nc21lbnNjaBqUA0VnV0tBUUlJQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVFzMk5EZzFVR2hQZEVoNldZSUJDM0IwTUZsMlptNW9SMmRKZ2dFTFZtbHVTbTFJTFhWcFpGbUNBUXRaYlZOdGVXMUlVbTVGUllJQkMxUm5aa2xpYVVoRFQweHZnZ0VMYkVOcE5rNWZkWEV6ZGtXQ0FRdFJTV3B4WlRKQ00xSmtVWUlCQzNFeWNGVnZkR3hZVUdWTmdnRUxNSGxRYm5abGRFTnRMVldDQVF0RlZUVldiSGsyTUZaSFZZSUJDMVZ1ZUZFd1ZFazBTVTF6Z2dFTGRXWndibmt4UzNoM1kxV0NBUXRrZFhwWFoxcEdTazUzUVlJQkMzSnVXSEV0TVc0d2JIUXdnZ0VMZGtocmNXUkROaTF5VDBtQ0FRdHVWR3hqWlZORlZGOWlPSUlCQzBRNFIyaHRVbWxKWm5oSmdnRUxNREZEVXkxcVZHRlpNVldDQVFzeWMwdHJTMHRMV0U4eU9JSUJDMk42Ykdkc05tNDVkbTlOGPHq0C4%3D"),

View file

@ -29,6 +29,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vbl9KrZxOF8", id: "vbl9KrZxOF8",
@ -53,6 +54,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "eMfROJt0a7Q", id: "eMfROJt0a7Q",
@ -77,6 +79,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1ktLEhfkBCI", id: "1ktLEhfkBCI",
@ -101,6 +104,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2hAlp3Khsnk", id: "2hAlp3Khsnk",
@ -125,6 +129,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CHixjhwY0ek", id: "CHixjhwY0ek",
@ -149,6 +154,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8YXKgZ393Ec", id: "8YXKgZ393Ec",
@ -173,6 +179,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KFNznAXnjXc", id: "KFNznAXnjXc",
@ -197,6 +204,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hDhJeJZmTDA", id: "hDhJeJZmTDA",
@ -221,6 +229,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "6kKSDXiip_8", id: "6kKSDXiip_8",
@ -245,6 +254,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vfzlr70ogaI", id: "vfzlr70ogaI",
@ -269,6 +279,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Fjth6cKGI88", id: "Fjth6cKGI88",
@ -293,6 +304,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fznwvW9Kn4s", id: "fznwvW9Kn4s",
@ -317,6 +329,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Jore0zZW-_M", id: "Jore0zZW-_M",
@ -341,6 +354,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_THM-2Ph-6I", id: "_THM-2Ph-6I",
@ -365,6 +379,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "koJAGIUlnD0", id: "koJAGIUlnD0",
@ -389,6 +404,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4tvQPrHcR4w", id: "4tvQPrHcR4w",
@ -413,6 +429,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CUh6MTvB_4E", id: "CUh6MTvB_4E",
@ -437,6 +454,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4TWR90KJl84", id: "4TWR90KJl84",
@ -461,6 +479,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Cw7eMibV-Xk", id: "Cw7eMibV-Xk",
@ -485,6 +504,7 @@ MusicSearchResult(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlRQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVF0YVpXVnljbTUxVEdrMVJZSUJDM1ppYkRsTGNscDRUMFk0Z2dFTFpVMW1VazlLZERCaE4xR0NBUXN4YTNSTVJXaG1hMEpEU1lJQkN6Sm9RV3h3TTB0b2MyNXJnZ0VMUTBocGVHcG9kMWt3Wld1Q0FRczRXVmhMWjFvek9UTkZZNElCQzB0R1RucHVRVmh1YWxoamdnRUxhRVJvU21WS1dtMVVSRUdDQVFzMmEwdFRSRmhwYVhCZk9JSUJDM1ptZW14eU56QnZaMkZKZ2dFTFJtcDBhRFpqUzBkSk9EaUNBUXRtZW01M2RsYzVTMjQwYzRJQkMwcHZjbVV3ZWxwWExWOU5nZ0VMWDFSSVRTMHlVR2d0TmttQ0FRdHJiMHBCUjBsVmJHNUVNSUlCQ3pSMGRsRlFja2hqVWpSM2dnRUxRMVZvTmsxVWRrSmZORVdDQVFzMFZGZFNPVEJMU213NE5JSUJDME4zTjJWTmFXSldMVmhyGPHq0C4%3D"), ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlRQVVnVWFnd1FBeEFFRUFrUURoQUtFQVdDQVF0YVpXVnljbTUxVEdrMVJZSUJDM1ppYkRsTGNscDRUMFk0Z2dFTFpVMW1VazlLZERCaE4xR0NBUXN4YTNSTVJXaG1hMEpEU1lJQkN6Sm9RV3h3TTB0b2MyNXJnZ0VMUTBocGVHcG9kMWt3Wld1Q0FRczRXVmhMWjFvek9UTkZZNElCQzB0R1RucHVRVmh1YWxoamdnRUxhRVJvU21WS1dtMVVSRUdDQVFzMmEwdFRSRmhwYVhCZk9JSUJDM1ptZW14eU56QnZaMkZKZ2dFTFJtcDBhRFpqUzBkSk9EaUNBUXRtZW01M2RsYzVTMjQwYzRJQkMwcHZjbVV3ZWxwWExWOU5nZ0VMWDFSSVRTMHlVR2d0TmttQ0FRdHJiMHBCUjBsVmJHNUVNSUlCQ3pSMGRsRlFja2hqVWpSM2dnRUxRMVZvTmsxVWRrSmZORVdDQVFzMFZGZFNPVEJMU213NE5JSUJDME4zTjJWTmFXSldMVmhyGPHq0C4%3D"),

View file

@ -1,5 +1,5 @@
--- ---
source: src/client/music_history.rs source: src/client/music_userdata.rs
expression: map_res.c expression: map_res.c
--- ---
Paginator( Paginator(
@ -37,6 +37,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -73,6 +74,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -109,6 +111,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -145,6 +148,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -181,6 +185,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -217,6 +222,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -257,6 +263,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -285,6 +292,7 @@ Paginator(
track_type: episode, track_type: episode,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Today"), playback_date_txt: Some("Today"),
@ -321,6 +329,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -357,6 +366,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -393,6 +403,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -429,6 +440,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -469,6 +481,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -505,6 +518,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -541,6 +555,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -577,6 +592,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -617,6 +633,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -653,6 +670,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -689,6 +707,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -725,6 +744,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -761,6 +781,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -797,6 +818,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),
@ -829,6 +851,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
playback_date: "[date]", playback_date: "[date]",
playback_date_txt: Some("Last week"), playback_date_txt: Some("Last week"),

View file

@ -28,6 +28,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "f9g6NCHQrcE", id: "f9g6NCHQrcE",
@ -56,6 +57,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CAVfEwrwT_o", id: "CAVfEwrwT_o",
@ -84,6 +86,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "VUr9JZQ8F2g", id: "VUr9JZQ8F2g",
@ -108,6 +111,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XQat6rNNbdQ", id: "XQat6rNNbdQ",
@ -132,6 +136,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "EQyU6fGDn0c", id: "EQyU6fGDn0c",
@ -156,6 +161,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g4poKgQZX6w", id: "g4poKgQZX6w",
@ -180,6 +186,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "YTHr7gxwYUQ", id: "YTHr7gxwYUQ",
@ -204,6 +211,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "MfCSDn6q6j4", id: "MfCSDn6q6j4",
@ -228,6 +236,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "gx9KFXb5x_o", id: "gx9KFXb5x_o",
@ -252,6 +261,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "d7R7DQ5tlQo", id: "d7R7DQ5tlQo",
@ -276,6 +286,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cZPjgcqHSa8", id: "cZPjgcqHSa8",
@ -300,6 +311,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ogDLdREonWY", id: "ogDLdREonWY",
@ -324,6 +336,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pRQpKprUUPY", id: "pRQpKprUUPY",
@ -348,6 +361,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "qZoQw9b4uCo", id: "qZoQw9b4uCo",
@ -372,6 +386,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "q23qghoF6Nk", id: "q23qghoF6Nk",
@ -396,6 +411,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "yU0aKa7PFBg", id: "yU0aKa7PFBg",
@ -420,6 +436,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DVCAqvypaCc", id: "DVCAqvypaCc",
@ -444,6 +461,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XdnI7sm6LeQ", id: "XdnI7sm6LeQ",
@ -468,6 +486,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KcOXNSJtFLg", id: "KcOXNSJtFLg",
@ -492,6 +511,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "K0UxHXZwgsg", id: "K0UxHXZwgsg",
@ -516,6 +536,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "eyyNwOSQ3Yg", id: "eyyNwOSQ3Yg",
@ -540,6 +561,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1yskotqNuXI", id: "1yskotqNuXI",
@ -564,6 +586,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "C03n4AAiL9w", id: "C03n4AAiL9w",
@ -588,6 +611,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "a2wNRTKRusM", id: "a2wNRTKRusM",
@ -612,6 +636,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AIf61iHwWMQ", id: "AIf61iHwWMQ",
@ -636,6 +661,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BixqbSRjY2Y", id: "BixqbSRjY2Y",
@ -660,6 +686,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Acgy-3d4P6o", id: "Acgy-3d4P6o",
@ -684,6 +711,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5M_yA9M7yNc", id: "5M_yA9M7yNc",
@ -708,6 +736,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PjJuezhos3U", id: "PjJuezhos3U",
@ -732,6 +761,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XMutaJI2-kc", id: "XMutaJI2-kc",
@ -756,6 +786,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Xac6Q7hcZkQ", id: "Xac6Q7hcZkQ",
@ -780,6 +811,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "JfwjsjBcDoU", id: "JfwjsjBcDoU",
@ -804,6 +836,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zshiQUV3ohw", id: "zshiQUV3ohw",
@ -828,6 +861,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g1eTAt1_VAM", id: "g1eTAt1_VAM",
@ -856,6 +890,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "c3rLrFC8igY", id: "c3rLrFC8igY",
@ -880,6 +915,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: true,
), ),
TrackItem( TrackItem(
id: "1im4DNEYzEM", id: "1im4DNEYzEM",
@ -908,6 +944,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8BUxw9ocM2s", id: "8BUxw9ocM2s",
@ -932,6 +969,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g4cSpnGbHPE", id: "g4cSpnGbHPE",
@ -960,6 +998,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1Sdj9MiCowQ", id: "1Sdj9MiCowQ",
@ -988,6 +1027,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2DbR35g-0ZY", id: "2DbR35g-0ZY",
@ -1012,6 +1052,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "j09hpp3AxIE", id: "j09hpp3AxIE",
@ -1036,6 +1077,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "J3GN6JXjV3g", id: "J3GN6JXjV3g",
@ -1060,6 +1102,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "pULl-p02upM", id: "pULl-p02upM",
@ -1084,6 +1127,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "O6By8JeCtQQ", id: "O6By8JeCtQQ",
@ -1108,6 +1152,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "NGn3IYQ7M7E", id: "NGn3IYQ7M7E",
@ -1132,6 +1177,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "o43oI5x86dI", id: "o43oI5x86dI",
@ -1156,6 +1202,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7TNqUrINxzs", id: "7TNqUrINxzs",
@ -1180,6 +1227,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "f3BD5Zm3cp0", id: "f3BD5Zm3cp0",
@ -1208,6 +1256,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "sF4yTDp95Eo", id: "sF4yTDp95Eo",
@ -1232,6 +1281,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1EwLNHg6ejY", id: "1EwLNHg6ejY",
@ -1256,6 +1306,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-l75qaSDWe8", id: "-l75qaSDWe8",
@ -1280,6 +1331,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7h7ntYLLrfQ", id: "7h7ntYLLrfQ",
@ -1304,6 +1356,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ApUl3Ops69M", id: "ApUl3Ops69M",
@ -1328,6 +1381,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2YcJ8Wightw", id: "2YcJ8Wightw",
@ -1352,6 +1406,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "W3q8Od5qJio", id: "W3q8Od5qJio",
@ -1376,6 +1431,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WPFLAjmWCtk", id: "WPFLAjmWCtk",
@ -1400,6 +1456,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tC76tIp0kBk", id: "tC76tIp0kBk",
@ -1424,6 +1481,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kiMG_JV2gbo", id: "kiMG_JV2gbo",
@ -1448,6 +1506,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "CrYYg_atdtk", id: "CrYYg_atdtk",
@ -1472,6 +1531,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XTPGpBBwt1w", id: "XTPGpBBwt1w",
@ -1496,6 +1556,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "uC08L4xxjNM", id: "uC08L4xxjNM",
@ -1520,6 +1581,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5fAoV_AAMf0", id: "5fAoV_AAMf0",
@ -1544,6 +1606,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "u5Vz7obL460", id: "u5Vz7obL460",
@ -1568,6 +1631,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ZPJlyRv_IGI", id: "ZPJlyRv_IGI",
@ -1592,6 +1656,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "s2SLbln-JwE", id: "s2SLbln-JwE",
@ -1616,6 +1681,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "28xHtRw6pG8", id: "28xHtRw6pG8",
@ -1640,6 +1706,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "joWoKqUTRvc", id: "joWoKqUTRvc",
@ -1664,6 +1731,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "XNMFTqhcNrE", id: "XNMFTqhcNrE",
@ -1688,6 +1756,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "v3vPLgJ9FX8", id: "v3vPLgJ9FX8",
@ -1716,6 +1785,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UFXOd179kOA", id: "UFXOd179kOA",
@ -1740,6 +1810,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4xRsDnKgHZc", id: "4xRsDnKgHZc",
@ -1764,6 +1835,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "mE3IjoEqMqY", id: "mE3IjoEqMqY",
@ -1788,6 +1860,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "E7e5vxKerqA", id: "E7e5vxKerqA",
@ -1812,6 +1885,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "axmZ_5Rx4Go", id: "axmZ_5Rx4Go",
@ -1836,6 +1910,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "44Ig6BsOCYA", id: "44Ig6BsOCYA",
@ -1860,6 +1935,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "3iLBFEJjdN0", id: "3iLBFEJjdN0",
@ -1884,6 +1960,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "M-ncq2eHF_k", id: "M-ncq2eHF_k",
@ -1908,6 +1985,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-AJoJ-ggiKI", id: "-AJoJ-ggiKI",
@ -1932,6 +2010,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "cgb-zp9DDHg", id: "cgb-zp9DDHg",
@ -1960,6 +2039,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Q7ZXg3KQLt0", id: "Q7ZXg3KQLt0",
@ -1984,6 +2064,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ysAEZOwp5rM", id: "ysAEZOwp5rM",
@ -2008,6 +2089,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "m5vfng33SVE", id: "m5vfng33SVE",
@ -2032,6 +2114,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "yMfgjVlGbUE", id: "yMfgjVlGbUE",
@ -2056,6 +2139,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OQIYEPe6DWY", id: "OQIYEPe6DWY",
@ -2080,6 +2164,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "5FS8RIH7BpI", id: "5FS8RIH7BpI",
@ -2104,6 +2189,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "zSRKgFB9piY", id: "zSRKgFB9piY",
@ -2128,6 +2214,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "e4eHhgwHCME", id: "e4eHhgwHCME",
@ -2156,6 +2243,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "q3hZvho7jNk", id: "q3hZvho7jNk",
@ -2180,6 +2268,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0nWysyj_Z4Y", id: "0nWysyj_Z4Y",
@ -2204,6 +2293,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "aGCcLWU0OVo", id: "aGCcLWU0OVo",
@ -2228,6 +2318,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OQsXLK4MeEA", id: "OQsXLK4MeEA",
@ -2252,6 +2343,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "xm7dxIqOO2M", id: "xm7dxIqOO2M",
@ -2276,6 +2368,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "jlaaByab4Zk", id: "jlaaByab4Zk",
@ -2304,6 +2397,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "KG9-jSqXz4U", id: "KG9-jSqXz4U",
@ -2328,6 +2422,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "7dISZnwsBSA", id: "7dISZnwsBSA",
@ -2352,6 +2447,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "F_PPdS-PB14", id: "F_PPdS-PB14",
@ -2376,6 +2472,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DMg9idvVY8M", id: "DMg9idvVY8M",
@ -2400,6 +2497,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DGEmoSFI94Y", id: "DGEmoSFI94Y",
@ -2424,6 +2522,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "BtZufymxHvE", id: "BtZufymxHvE",
@ -2452,6 +2551,7 @@ Paginator(
track_type: video, track_type: video,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("4qmFsgI8EiRWTFBMNWREeDY4MVQ0YlI3WkYxSXVXek92MW9tbFJiRTdQaUoaFGVnZFFWRHBEVGtGQ2tnRURDTG9F"), ctoken: Some("4qmFsgI8EiRWTFBMNWREeDY4MVQ0YlI3WkYxSXVXek92MW9tbFJiRTdQaUoaFGVnZFFWRHBEVGtGQ2tnRURDTG9F"),

View file

@ -56,6 +56,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hh5GKVa8VtM", id: "hh5GKVa8VtM",
@ -108,6 +109,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RdU3F5vN3_s", id: "RdU3F5vN3_s",
@ -160,6 +162,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OXWz_x6-dro", id: "OXWz_x6-dro",
@ -212,6 +215,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ghrlZIMDzbM", id: "ghrlZIMDzbM",
@ -264,6 +268,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "QiziJ40kTz0", id: "QiziJ40kTz0",
@ -316,6 +321,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "950BdJKBhGo", id: "950BdJKBhGo",
@ -368,6 +374,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "tkzYyEp4zB4", id: "tkzYyEp4zB4",
@ -420,6 +427,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ffqliB42Nh4", id: "ffqliB42Nh4",
@ -472,6 +480,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vFFT1iAUNDE", id: "vFFT1iAUNDE",
@ -528,6 +537,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8JXc4idKS_c", id: "8JXc4idKS_c",
@ -580,6 +590,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4JJFrjkRxmo", id: "4JJFrjkRxmo",
@ -632,6 +643,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0EK_M2taRIM", id: "0EK_M2taRIM",
@ -684,6 +696,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "04tYkKUPPv4", id: "04tYkKUPPv4",
@ -736,6 +749,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "W0x7GcZkvH4", id: "W0x7GcZkvH4",
@ -788,6 +802,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "INLFlN-PZq4", id: "INLFlN-PZq4",
@ -840,6 +855,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "GhL8GUjXEfk", id: "GhL8GUjXEfk",
@ -892,6 +908,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "TaZkqPK0sbw", id: "TaZkqPK0sbw",
@ -948,6 +965,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ogKU5EQ0Wn0", id: "ogKU5EQ0Wn0",
@ -1000,6 +1018,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "g92HIac9ufA", id: "g92HIac9ufA",
@ -1052,6 +1071,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_E6gDU0m_hk", id: "_E6gDU0m_hk",
@ -1104,6 +1124,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FrEDny55ch8", id: "FrEDny55ch8",
@ -1156,6 +1177,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "-uOShlFu1v8", id: "-uOShlFu1v8",
@ -1208,6 +1230,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "PyyT5tHbOLw", id: "PyyT5tHbOLw",
@ -1260,6 +1283,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("CBkSSBILUHl5VDV0SGJPTHciEVJEQU1WTTduaWdYUVMxWGIwMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0UWVYbFVOWFJJWWs5TWR3"), ctoken: Some("CBkSSBILUHl5VDV0SGJPTHciEVJEQU1WTTduaWdYUVMxWGIwMg53QUVCOGdFQ2VBRSUzRDgY0AEB-gEQQzcxNUY2RDFGQjIwNEQwQRgKggEVUFQ6RWd0UWVYbFVOWFJJWWs5TWR3"),

View file

@ -36,6 +36,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "0uSu-jHdDd4", id: "0uSu-jHdDd4",
@ -68,6 +69,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "11pkE_azpBQ", id: "11pkE_azpBQ",
@ -100,6 +102,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "1tJPy7XlfCQ", id: "1tJPy7XlfCQ",
@ -132,6 +135,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "2JpUBTLjfPA", id: "2JpUBTLjfPA",
@ -164,6 +168,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "6WiuMIp9B6Y", id: "6WiuMIp9B6Y",
@ -196,6 +201,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "8nfNNAlsTTA", id: "8nfNNAlsTTA",
@ -228,6 +234,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "C1U6oXpz4As", id: "C1U6oXpz4As",
@ -260,6 +267,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "DvKw0jTUN-s", id: "DvKw0jTUN-s",
@ -292,6 +300,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "GDSVX--bsRU", id: "GDSVX--bsRU",
@ -324,6 +333,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "I-ArzgPbNx8", id: "I-ArzgPbNx8",
@ -356,6 +366,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OElgvIuT8TY", id: "OElgvIuT8TY",
@ -388,6 +399,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "RGlOEBJyhrc", id: "RGlOEBJyhrc",
@ -420,6 +432,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "UUCM1WR611g", id: "UUCM1WR611g",
@ -452,6 +465,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "WlzrZsEtWbs", id: "WlzrZsEtWbs",
@ -484,6 +498,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "apY7iYoYtD8", id: "apY7iYoYtD8",
@ -516,6 +531,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "azSEPwrxG2c", id: "azSEPwrxG2c",
@ -548,6 +564,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "b9FNHTk-tAM", id: "b9FNHTk-tAM",
@ -580,6 +597,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "eAeGr78VYxM", id: "eAeGr78VYxM",
@ -612,6 +630,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "efCzrXOWM0Q", id: "efCzrXOWM0Q",
@ -644,6 +663,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "fbmHQLiF1qs", id: "fbmHQLiF1qs",
@ -676,6 +696,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "h0qhAXLom-Y", id: "h0qhAXLom-Y",
@ -708,6 +729,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hTL2vAvAbNM", id: "hTL2vAvAbNM",
@ -740,6 +762,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "hptOG4EVgMs", id: "hptOG4EVgMs",
@ -772,6 +795,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "iRIlHsC8xL8", id: "iRIlHsC8xL8",
@ -804,6 +828,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("4qmFsgJcEhRGRW11c2ljX2xpa2VkX3ZpZGVvcxpEQ0JwNkprTkNhMUZIVW05SlEwRkZVVUZvYjBOYVZ6UnBSRUZxWXpsaVF6ZENhRU4yT1ZwdFRVRjNnZ01HS2dRSUFCQUI%3D"), ctoken: Some("4qmFsgJcEhRGRW11c2ljX2xpa2VkX3ZpZGVvcxpEQ0JwNkprTkNhMUZIVW05SlEwRkZVVUZvYjBOYVZ6UnBSRUZxWXpsaVF6ZENhRU4yT1ZwdFRVRjNnZ01HS2dRSUFCQUI%3D"),

View file

@ -36,6 +36,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "vMZqNPZADFw", id: "vMZqNPZADFw",
@ -68,6 +69,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "C8B-nBnB7Bk", id: "C8B-nBnB7Bk",
@ -100,6 +102,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "29MOu6Y781I", id: "29MOu6Y781I",
@ -132,6 +135,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "AdvPpJVvyEg", id: "AdvPpJVvyEg",
@ -164,6 +168,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "kv3Z269PQvE", id: "kv3Z269PQvE",
@ -196,6 +201,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "y74ZqAkFkK4", id: "y74ZqAkFkK4",
@ -228,6 +234,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "ZVnqAUnj-1Y", id: "ZVnqAUnj-1Y",
@ -260,6 +267,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "REmUidcJt5I", id: "REmUidcJt5I",
@ -292,6 +300,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "63sEilefjtQ", id: "63sEilefjtQ",
@ -324,6 +333,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_LGy1K5vmq8", id: "_LGy1K5vmq8",
@ -356,6 +366,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Ak98OIfed8o", id: "Ak98OIfed8o",
@ -388,6 +399,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "_aSqdZKxcuU", id: "_aSqdZKxcuU",
@ -420,6 +432,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "6Lb4bmEEfnY", id: "6Lb4bmEEfnY",
@ -452,6 +465,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "4lrp5FWFIak", id: "4lrp5FWFIak",
@ -484,6 +498,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "Kk8vT1o_gYE", id: "Kk8vT1o_gYE",
@ -524,6 +539,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "FbUrY0GdO88", id: "FbUrY0GdO88",
@ -556,6 +572,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "OFesVwAdT80", id: "OFesVwAdT80",
@ -588,6 +605,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "lNeJjPPKE1g", id: "lNeJjPPKE1g",
@ -620,6 +638,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
TrackItem( TrackItem(
id: "SW_woyyA1Bg", id: "SW_woyyA1Bg",
@ -652,6 +671,7 @@ Paginator(
track_type: track, track_type: track,
track_nr: None, track_nr: None,
by_va: false, by_va: false,
unavailable: false,
), ),
], ],
ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlJQVVnb2Fnd1FBeEFFRUFrUURoQUtFQVdDQVF0eVRuTkpVMEV0YTFkNlRZSUJDM1pOV25GT1VGcEJSRVozZ2dFTFF6aENMVzVDYmtJM1FtdUNBUXN5T1UxUGRUWlpOemd4U1lJQkMwRmtkbEJ3U2xaMmVVVm5nZ0VMYTNZeldqSTJPVkJSZGtXQ0FRdDVOelJhY1VGclJtdExOSUlCQzFwV2JuRkJWVzVxTFRGWmdnRUxVa1Z0Vldsa1kwcDBOVW1DQVFzMk0zTkZhV3hsWm1wMFVZSUJDMTlNUjNreFN6VjJiWEU0Z2dFTFFXczVPRTlKWm1Wa09HLUNBUXRmWVZOeFpGcExlR04xVllJQkN6Wk1ZalJpYlVWRlptNVpnZ0VMTkd4eWNEVkdWMFpKWVd1Q0FRdExhemgyVkRGdlgyZFpSWUlCQzBaaVZYSlpNRWRrVHpnNGdnRUxUMFpsYzFaM1FXUlVPRENDQVF0c1RtVkthbEJRUzBVeFo0SUJDMU5YWDNkdmVYbEJNVUpuGPHq0C4%3D"), ctoken: Some("EqQDEgtibGFjayBtYW1iYRqUA0VnV0tBUUlJQVVnb2Fnd1FBeEFFRUFrUURoQUtFQVdDQVF0eVRuTkpVMEV0YTFkNlRZSUJDM1pOV25GT1VGcEJSRVozZ2dFTFF6aENMVzVDYmtJM1FtdUNBUXN5T1UxUGRUWlpOemd4U1lJQkMwRmtkbEJ3U2xaMmVVVm5nZ0VMYTNZeldqSTJPVkJSZGtXQ0FRdDVOelJhY1VGclJtdExOSUlCQzFwV2JuRkJWVzVxTFRGWmdnRUxVa1Z0Vldsa1kwcDBOVW1DQVFzMk0zTkZhV3hsWm1wMFVZSUJDMTlNUjNreFN6VjJiWEU0Z2dFTFFXczVPRTlKWm1Wa09HLUNBUXRmWVZOeFpGcExlR04xVllJQkN6Wk1ZalJpYlVWRlptNVpnZ0VMTkd4eWNEVkdWMFpKWVd1Q0FRdExhemgyVkRGdlgyZFpSWUlCQzBaaVZYSlpNRWRrVHpnNGdnRUxUMFpsYzFaM1FXUlVPRENDQVF0c1RtVkthbEJRUzBVeFo0SUJDMU5YWDNkdmVYbEJNVUpuGPHq0C4%3D"),

View file

@ -7,7 +7,7 @@ use crate::{
error::{Error, ExtractionError}, error::{Error, ExtractionError},
model::{ model::{
paginator::{ContinuationEndpoint, Paginator}, paginator::{ContinuationEndpoint, Paginator},
ChannelItem, HistoryItem, PlaylistItem, VideoItem, ChannelItem, HistoryItem, Playlist, PlaylistItem, VideoItem,
}, },
serializer::MapResult, serializer::MapResult,
}; };
@ -148,6 +148,28 @@ impl RustyPipeQuery {
) )
.await .await
} }
/// Get all liked videos of the logged-in user
///
/// Requires authentication cookies.
pub async fn liked_videos(&self) -> Result<Playlist, Error> {
self.clone()
.authenticated()
.playlist("LL")
.await
.map_err(crate::util::map_internal_playlist_err)
}
/// Get the "Watch later" playlist of the logged-in user
///
/// Requires authentication cookies.
pub async fn watch_later(&self) -> Result<Playlist, Error> {
self.clone()
.authenticated()
.playlist("WL")
.await
.map_err(crate::util::map_internal_playlist_err)
}
} }
impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::History { impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::History {
@ -181,14 +203,13 @@ impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::History {
mapper.map_response(contents); mapper.map_response(contents);
mapper.conv_history_items( mapper.conv_history_items(
header.map(|h| h.item_section_header_renderer.title), header.map(|h| h.item_section_header_renderer.title),
ctx.utc_offset,
&mut map_res, &mut map_res,
); );
} }
response::YouTubeListItem::ContinuationItemRenderer { response::YouTubeListItem::ContinuationItemRenderer(ep) => {
continuation_endpoint,
} => {
if ctoken.is_none() { if ctoken.is_none() {
ctoken = Some(continuation_endpoint.continuation_command.token); ctoken = ep.continuation_endpoint.into_token();
} }
} }
_ => {} _ => {}
@ -257,7 +278,7 @@ mod tests {
#[test] #[test]
fn map_history() { fn map_history() {
let json_path = path!(*TESTFILES / "history" / "history.json"); let json_path = path!(*TESTFILES / "userdata" / "history.json");
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
let history: response::History = let history: response::History =
@ -277,7 +298,7 @@ mod tests {
#[test] #[test]
fn map_subscription_feed() { fn map_subscription_feed() {
let json_path = path!(*TESTFILES / "history" / "subscription_feed.json"); let json_path = path!(*TESTFILES / "userdata" / "subscription_feed.json");
let json_file = File::open(json_path).unwrap(); let json_file = File::open(json_path).unwrap();
let history: response::History = let history: response::History =

View file

@ -180,7 +180,12 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
// so we ignore parse errors here for now // so we ignore parse errors here for now
like_text.and_then(|txt| util::parse_numeric(&txt).ok()), like_text.and_then(|txt| util::parse_numeric(&txt).ok()),
date_text.as_deref().and_then(|txt| { date_text.as_deref().and_then(|txt| {
timeago::parse_textual_date_or_warn(ctx.lang, txt, &mut warnings) timeago::parse_textual_date_or_warn(
ctx.lang,
ctx.utc_offset,
txt,
&mut warnings,
)
}), }),
date_text, date_text,
view_count view_count
@ -203,11 +208,10 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
) )
}); });
let comment_ctoken = comment_ctoken_section.map(|s| { let comment_ctoken = comment_ctoken_section.and_then(|s| {
s.continuation_item_renderer s.continuation_item_renderer
.continuation_endpoint .continuation_endpoint
.continuation_command .into_token()
.token
}); });
let (owner, description, is_ccommons) = match secondary_info { let (owner, description, is_ccommons) = match secondary_info {
@ -328,7 +332,7 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
.sub_menu_items; .sub_menu_items;
items items
.try_swap_remove(1) .try_swap_remove(1)
.map(|c| c.service_endpoint.continuation_command.token) .and_then(|c| c.service_endpoint.into_token())
}); });
Ok(MapResult { Ok(MapResult {
@ -448,7 +452,9 @@ impl MapResponse<Paginator<Comment>> for response::VideoComments {
} }
} }
response::video_details::CommentListItem::ContinuationItemRenderer(cont) => { response::video_details::CommentListItem::ContinuationItemRenderer(cont) => {
ctoken = Some(cont.token()); if ctoken.is_none() {
ctoken = cont.into_token();
}
} }
response::video_details::CommentListItem::CommentsHeaderRenderer { count_text } => { response::video_details::CommentListItem::CommentsHeaderRenderer { count_text } => {
comment_count = count_text comment_count = count_text
@ -515,7 +521,9 @@ fn map_replies(
)) ))
} }
response::video_details::CommentListItem::ContinuationItemRenderer(cont) => { response::video_details::CommentListItem::ContinuationItemRenderer(cont) => {
reply_ctoken = Some(cont.token()); if reply_ctoken.is_none() {
reply_ctoken = cont.into_token();
}
None None
} }
_ => None, _ => None,

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use reqwest::Client; use reqwest::Client;
use ress::tokens::Token; use ress::tokens::{Keyword, Punct, Token};
use rquickjs::{Context, Runtime}; use rquickjs::{Context, Runtime};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -39,7 +39,7 @@ impl DeobfData {
if let Err(e) = &res { if let Err(e) = &res {
if let Some(reporter) = reporter { if let Some(reporter) = reporter {
let report = Report { let report = Report {
info: RustyPipeInfo::new(None), info: RustyPipeInfo::new(None, None),
level: Level::ERR, level: Level::ERR,
operation: "extract_deobf", operation: "extract_deobf",
error: Some(e.to_string()), error: Some(e.to_string()),
@ -106,7 +106,7 @@ impl Deobfuscator {
.with(|ctx| call_fn(&ctx, DEOBF_NSIG_FUNC_NAME, nsig))?; .with(|ctx| call_fn(&ctx, DEOBF_NSIG_FUNC_NAME, nsig))?;
tracing::trace!("deobf nsig: {nsig} -> {res}"); tracing::trace!("deobf nsig: {nsig} -> {res}");
if res.starts_with("enhanced_except_") || res.ends_with(nsig) { if res.starts_with("enhanced_except_") || res.ends_with(nsig) {
return Err(DeobfError::Other("nsig fn returned an exception")); return Err(DeobfError::Other("nsig fn returned an exception".into()));
} }
Ok(res) Ok(res)
} }
@ -134,55 +134,21 @@ fn caller_function(mapped_name: &str, fn_name: &str) -> String {
} }
fn get_sig_fn(player_js: &str) -> Result<String, DeobfError> { fn get_sig_fn(player_js: &str) -> Result<String, DeobfError> {
let dfunc_name = get_sig_fn_name(player_js)?; let name = get_sig_fn_name(player_js)?;
let code = extract_js_fn(player_js, &name)?;
let js_fn = format!("{}{}", code, caller_function(DEOBF_SIG_FUNC_NAME, &name));
let function_pattern_str = format!(
r#"({}=function\([\w]+\)\{{.+?\}})"#,
dfunc_name.replace('$', "\\$")
);
let function_pattern = Regex::new(&function_pattern_str)
.map_err(|_| DeobfError::Other("could not parse sig fn pattern regex"))?;
let deobfuscate_function = format!(
"var {};",
&function_pattern
.captures(player_js)
.ok_or(DeobfError::Extraction("sig fn"))?[1]
);
let helper_object_name_pattern = Regex::new(r";([\w\$]{2,3})\...\(").unwrap();
let helper_object_name = helper_object_name_pattern
.captures(&deobfuscate_function)
.ok_or(DeobfError::Extraction("sig fn helper object name"))?
.get(1)
.unwrap()
.as_str();
let helper_pattern_str = format!(
r#"(var {}=\{{.+?\}}\}};)"#,
helper_object_name.replace('$', "\\$")
);
let helper_pattern = Regex::new(&helper_pattern_str)
.map_err(|_| DeobfError::Other("could not parse helper pattern regex"))?;
let player_js_nonl = player_js.replace('\n', "");
let helper_object = &helper_pattern
.captures(&player_js_nonl)
.ok_or(DeobfError::Extraction("sig fn helper object"))?[1];
let js_fn = helper_object.to_owned()
+ &deobfuscate_function
+ &caller_function(DEOBF_SIG_FUNC_NAME, &dfunc_name);
tracing::trace!("sig_fn: {js_fn}"); tracing::trace!("sig_fn: {js_fn}");
verify_fn(&js_fn, DEOBF_SIG_FUNC_NAME)?; verify_fn(&js_fn, DEOBF_SIG_FUNC_NAME)?;
tracing::debug!("successfully extracted sig fn `{dfunc_name}`"); tracing::debug!("successfully extracted sig fn `{name}`");
Ok(js_fn) Ok(js_fn)
} }
fn get_nsig_fn_names(player_js: &str) -> impl Iterator<Item = String> + '_ { fn get_nsig_fn_names(player_js: &str) -> impl Iterator<Item = String> + '_ {
static FUNCTION_NAME_REGEX: Lazy<Regex> = Lazy::new(|| { static FUNCTION_NAME_REGEX: Lazy<Regex> = Lazy::new(|| {
// x.get( .. y=functionName[array_num](z) .. x.set( // ( ==="index.m3u8" OR "index.m3u8"=== ) .. delete .. y=functionName[array_num](z)
Regex::new(r#"(?:[\w$]\.get\(|index\.m3u8).+[a-zA-Z]=([\w$]{2,})(?:\[(\d+)\])?\([a-zA-Z0-9]\).+[a-zA-Z0-9]\.set\("#) Regex::new(r#"(?:(?:===(?:[\w$]+\[\d+\]|"index\.m3u8"))|(?:(?:[\w$]+\[\d+\]|"index\.m3u8")===)).+\bdelete\b.+\b[a-zA-Z]=([\w$]{2,})(?:\[(\d+)\])?\([a-zA-Z0-9]\)"#)
.unwrap() .unwrap()
}); });
@ -206,26 +172,71 @@ fn get_nsig_fn_names(player_js: &str) -> impl Iterator<Item = String> + '_ {
}) })
} }
fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result<String, DeobfError> { fn extract_js_fn(js: &str, name: &str) -> Result<String, DeobfError> {
let function_base_re = Regex::new(&format!(r#"{}\s*=\s*function\("#, regex::escape(name)))
.map_err(|e| DeobfError::Other(format!("parsing regex for {name}: {e}").into()))?;
let offset = function_base_re
.find(js)
.ok_or(DeobfError::Extraction("could not find function base"))?
.start();
let scan = ress::Scanner::new(&js[offset..]); let scan = ress::Scanner::new(&js[offset..]);
let mut state = 0; let mut state = 0;
let mut level = 0;
let mut start = 0; #[derive(Default, Clone, PartialEq, Eq)]
let mut end = 0; struct Level {
brace: isize,
paren: isize,
bracket: isize,
}
let mut level = Level::default();
let mut start = 0usize;
let mut end = 0usize;
let mut period_before = false; let mut period_before = false;
let mut last_ident = None; let mut function_before = false;
let mut idents: HashMap<String, usize> = HashMap::new(); let mut idents: HashMap<String, bool> = HashMap::new();
// Set if the current statement is a variable/function param definition
// First value is the brace level, second is true if we are on the right hand side of an assignment
let mut var_def_stmt: Option<(Level, bool)> = None;
let global_objects = [ let global_objects = [
"NaN", "Infinity", "Object", "Function", "Boolean", "Symbol", "Error", "Number", "BigInt", "globalThis",
"Math", "Date", "String", "RegExp", "Array", "Map", "Set", "NaN",
"undefined",
"Infinity",
"Object",
"Function",
"Boolean",
"Symbol",
"Error",
"Number",
"BigInt",
"Math",
"Date",
"String",
"RegExp",
"Array",
"Map",
"Set",
"eval",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"escape",
"unescape",
]; ];
for item in scan { for item in scan {
let it = item?; let it = item?;
let token = it.token; let token = it.token;
match state { match state {
// Looking for fn name // Looking for fn name
0 => { 0 => {
@ -236,47 +247,113 @@ fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result<String, DeobfErr
} }
// Looking for equals // Looking for equals
1 => { 1 => {
if token.matches_punct(ress::tokens::Punct::Equal) { if token.matches_punct(Punct::Equal) {
state = 2; state = 2;
} else { } else {
state = 0; state = 0;
} }
} }
2 => { 2 => {
// Looking for begin/end braces match &token {
if token.matches_punct(ress::tokens::Punct::OpenBrace) { Token::Punct(punct) => {
level += 1; let var_def_this_lvl = || {
} else if token.matches_punct(ress::tokens::Punct::CloseBrace) { var_def_stmt
level -= 1; .as_ref()
.map(|(x, _)| x == &level)
.unwrap_or_default()
};
if level == 0 { match punct {
end = it.span.end; Punct::OpenBrace => {
state = 3; level.brace += 1;
break; }
} Punct::CloseBrace => {
} if var_def_this_lvl() {
var_def_stmt = None;
}
level.brace -= 1;
// Looking for variable names if level.brace == 0 {
if let Token::Ident(id) = &token { end = it.span.end;
if !period_before { state = 3;
let id_str = id.to_string(); break;
if !global_objects.contains(&id_str.as_str()) { }
last_ident = Some(id.to_string()); }
Punct::OpenParen => {
level.paren += 1;
}
Punct::CloseParen => {
if var_def_this_lvl() {
var_def_stmt = None;
}
level.paren -= 1;
}
Punct::OpenBracket => {
level.bracket += 1;
}
Punct::CloseBracket => {
if var_def_this_lvl() {
var_def_stmt = None;
}
level.bracket -= 1;
}
Punct::SemiColon => {
if var_def_this_lvl() {
var_def_stmt = None;
}
}
Punct::Comma => {
if let Some((lvl, rhs)) = &mut var_def_stmt {
if lvl == &level {
*rhs = false;
}
}
}
Punct::Equal => {
if let Some((lvl, rhs)) = &mut var_def_stmt {
if lvl == &level {
*rhs = true;
}
}
}
_ => {}
} }
} }
} else if last_ident.is_some() Token::Keyword(kw) => match kw {
&& !token.matches_punct(ress::tokens::Punct::OpenParen) Keyword::Var(_) | Keyword::Let(_) | Keyword::Const(_) => {
{ var_def_stmt = Some((level.clone(), false));
let n = idents.entry(last_ident.unwrap()).or_default(); }
*n += 1; Keyword::Function(_) => {
last_ident = None; let mut l = level.clone();
} else { l.paren += 1;
last_ident = None; var_def_stmt = Some((l, false));
}
_ => {}
},
Token::Ident(id) => {
// Ignore object attributes
if !period_before && !global_objects.contains(&id.as_ref()) {
// If we are on the left hand side of a variable definition statement
// or after "function", mark the variable name as defined
if var_def_stmt
.as_ref()
.map(|(lvl, rhs)| lvl == &level && !rhs)
.unwrap_or_default()
|| function_before
{
idents.insert(id.to_string(), true);
} else {
idents.entry(id.to_string()).or_default();
}
}
}
_ => {}
} }
} }
_ => break, _ => break,
}; };
period_before = token.matches_punct(ress::tokens::Punct::Period); period_before = token.matches_punct(Punct::Period);
function_before = matches!(&token, Token::Keyword(Keyword::Function(_)));
} }
if state != 3 { if state != 3 {
@ -287,9 +364,10 @@ fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result<String, DeobfErr
let mut code = format!("var {};", &js[fn_range.clone()]); let mut code = format!("var {};", &js[fn_range.clone()]);
let rt = rquickjs::Runtime::new()?; let rt = rquickjs::Runtime::new()?;
for (ident, _) in idents.into_iter().filter(|(_, v)| *v == 1) { for (ident, _) in idents.into_iter().filter(|(_, v)| !v) {
let var_pattern_str = format!(r#"(^|[^\w$]){}\s*=[^=]"#, regex::escape(&ident)); let var_pattern_str = format!(r#"(^|[^\w$\.]){}\s*=[^=]"#, regex::escape(&ident));
let re = Regex::new(&var_pattern_str).unwrap(); let re = Regex::new(&var_pattern_str)
.map_err(|e| DeobfError::Other(format!("parsing regex for {ident}: {e}").into()))?;
let found_variable = re let found_variable = re
.captures_iter(js) .captures_iter(js)
.filter(|cap| { .filter(|cap| {
@ -347,13 +425,13 @@ fn extract_js_var(js: &str) -> Option<&str> {
if let Token::Punct(p) = &token { if let Token::Punct(p) = &token {
match p { match p {
ress::tokens::Punct::OpenBrace => braces.push(b'{'), Punct::OpenBrace => braces.push(b'{'),
ress::tokens::Punct::OpenBracket => braces.push(b'['), Punct::OpenBracket => braces.push(b'['),
ress::tokens::Punct::OpenParen => braces.push(b'('), Punct::OpenParen => braces.push(b'('),
ress::tokens::Punct::CloseBrace => close_brace(&mut braces, b'{')?, Punct::CloseBrace => close_brace(&mut braces, b'{')?,
ress::tokens::Punct::CloseBracket => close_brace(&mut braces, b'[')?, Punct::CloseBracket => close_brace(&mut braces, b'[')?,
ress::tokens::Punct::CloseParen => close_brace(&mut braces, b'(')?, Punct::CloseParen => close_brace(&mut braces, b'(')?,
ress::tokens::Punct::Comma | ress::tokens::Punct::SemiColon => { Punct::Comma | Punct::SemiColon => {
if braces.is_empty() { if braces.is_empty() {
end = it.span.start; end = it.span.start;
break; break;
@ -388,23 +466,19 @@ fn verify_fn(js_fn: &str, fn_name: &str) -> Result<(), DeobfError> {
})?; })?;
if res.is_empty() { if res.is_empty() {
return Err(DeobfError::Other("deobfuscation fn returned empty string")); return Err(DeobfError::Other(
"deobfuscation fn returned empty string".into(),
));
} }
if res.starts_with("enhanced_except_") || res.ends_with(&testinp) { if res.starts_with("enhanced_except_") || res.ends_with(&testinp) {
return Err(DeobfError::Other("nsig fn returned an exception")); return Err(DeobfError::Other("nsig fn returned an exception".into()));
} }
Ok(()) Ok(())
} }
fn get_nsig_fn(player_js: &str) -> Result<String, DeobfError> { fn get_nsig_fn(player_js: &str) -> Result<String, DeobfError> {
let extract_fn = |name: &str| -> Result<String, DeobfError> { let extract_fn = |name: &str| -> Result<String, DeobfError> {
let function_base = format!("{name}=function"); let code = extract_js_fn(player_js, name)?;
let offset = player_js
.find(&function_base)
.ok_or(DeobfError::Extraction("could not find function base"))?;
let code = extract_js_fn(player_js, offset, name)?;
let js_fn = format!("{}{}", code, caller_function(DEOBF_NSIG_FUNC_NAME, name)); let js_fn = format!("{}{}", code, caller_function(DEOBF_NSIG_FUNC_NAME, name));
tracing::trace!("nsig_fn: {js_fn}"); tracing::trace!("nsig_fn: {js_fn}");
verify_fn(&js_fn, DEOBF_NSIG_FUNC_NAME)?; verify_fn(&js_fn, DEOBF_NSIG_FUNC_NAME)?;
@ -472,7 +546,9 @@ mod tests {
std::fs::read_to_string(js_path).unwrap() std::fs::read_to_string(js_path).unwrap()
}); });
const SIG_DEOBF_FUNC: &str = r#"var qB={w8:function(a){a.reverse()},EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},Np:function(a,b){a.splice(0,b)}};var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};var deobf_sig=Rva;"#; const SIG_DEOBF_FUNC: &str = r#"var qB={w8:function(a){a.reverse()},
EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},
Np:function(a,b){a.splice(0,b)}}; var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};var deobf_sig=Rva;"#;
const NSIG_DEOBF_FUNC: &str = r#"var Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))}, const NSIG_DEOBF_FUNC: &str = r#"var Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))},
928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e}, 928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])}, b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},
@ -525,7 +601,7 @@ c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c
#[test] #[test]
fn t_extract_js_fn() { fn t_extract_js_fn() {
let base_js = "Wka = function(d){let x=10/2;return /,,[/,913,/](,)}/}let a = 42;"; let base_js = "Wka = function(d){let x=10/2;return /,,[/,913,/](,)}/}let a = 42;";
let res = extract_js_fn(base_js, 0, "Wka").unwrap(); let res = extract_js_fn(base_js, "Wka").unwrap();
assert_eq!( assert_eq!(
res, res,
"var Wka = function(d){let x=10/2;return /,,[/,913,/](,)}/};" "var Wka = function(d){let x=10/2;return /,,[/,913,/](,)}/};"
@ -536,7 +612,7 @@ c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c
fn t_extract_js_fn_eviljs() { fn t_extract_js_fn_eviljs() {
// Evil JavaScript code containing braces within strings and regular expressions // Evil JavaScript code containing braces within strings and regular expressions
let base_js = "Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];}//some={}random-padding+;"; let base_js = "Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];}//some={}random-padding+;";
let res = extract_js_fn(base_js, 0, "Wka").unwrap(); let res = extract_js_fn(base_js, "Wka").unwrap();
assert_eq!( assert_eq!(
res, res,
"var Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];};" "var Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];};"
@ -545,33 +621,43 @@ c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c
#[test] #[test]
fn t_extract_js_fn_outside_vars() { fn t_extract_js_fn_outside_vars() {
let base_js = "let a = 42;foo();var b=11;bar();Wka = function(d){var x=1+2+a*b;return x;}"; let base_js = "let a1 = 42;foo();var b1=11;var da=77;bar();Wka = function(da){var xy=1+2+a1*b1;return xy;}";
let res = extract_js_fn(base_js, 0, "Wka").unwrap(); let res = extract_js_fn(base_js, "Wka").unwrap();
// order of variables is non-reproducible // order of variables is non-reproducible
assert!( assert!(
res == "var a = 42; var b=11; var Wka = function(d){var x=1+2+a*b;return x;};" res == "var a1 = 42; var b1=11; var Wka = function(da){var xy=1+2+a1*b1;return xy;};"
|| res == "var b=11; var a = 42; var Wka = function(d){var x=1+2+a*b;return x;};", || res == "var b1=11; var a1 = 42; var Wka = function(da){var xy=1+2+a1*b1;return xy;};",
"got {res}" "got {res}"
); );
} }
#[test] #[test]
fn t_extract_js_fn_outside_vars2() { fn t_extract_js_fn_outside_vars2() {
let base_js = "{let a = {v1:1,v2:2}}foo();Wka = function(d){var x=1+2+a.v1;return x;}"; let base_js = "{let a1 = {v1:1,v2:2}}foo();Wka = function(d){var x=1+2+a1.v1;return x;}";
let res = extract_js_fn(base_js, 0, "Wka").unwrap(); let res = extract_js_fn(base_js, "Wka").unwrap();
assert_eq!( assert_eq!(
res, res,
"var a = {v1:1,v2:2}; var Wka = function(d){var x=1+2+a.v1;return x;};" "var a1 = {v1:1,v2:2}; var Wka = function(d){var x=1+2+a1.v1;return x;};"
); );
} }
#[test] #[test]
fn t_extract_js_fn_outside_vars3() { fn t_extract_js_fn_outside_vars3() {
let base_js = "Wka = function(d){var x=1+2+a[0];return x;};let a=[1,2,3]"; let base_js = "Wka = function(d){var x=1+2+a1[0];return x;};let a1=[1,2,3]";
let res = extract_js_fn(base_js, 0, "Wka").unwrap(); let res = extract_js_fn(base_js, "Wka").unwrap();
assert_eq!( assert_eq!(
res, res,
"var a=[1,2,3]; var Wka = function(d){var x=1+2+a[0];return x;};" "var a1=[1,2,3]; var Wka = function(d){var x=1+2+a1[0];return x;};"
);
}
#[test]
fn t_extract_js_fn_outside_vars4() {
let base_js = "let a0=123456;let a1=function(a){return a};let Wka = function(d){var x=1+2+a1();return x;}";
let res = extract_js_fn(base_js, "Wka").unwrap();
assert_eq!(
res,
"var a1=function(a){return a}; var Wka = function(d){var x=1+2+a1();return x;};"
); );
} }
@ -625,65 +711,88 @@ c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c
} }
// Test cases from https://github.com/yt-dlp/yt-dlp/blob/master/test/test_youtube_signature.py // Test cases from https://github.com/yt-dlp/yt-dlp/blob/master/test/test_youtube_signature.py
#[rstest]
#[case("6ed0d907", "AOq0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xx8j7v1pDL2QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJoOySqa0")]
#[case("3bb1f723", "MyOSJXtKI3m-uME_jv7-pT12gOFC02RFkGoqWpzE0Cs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA")]
#[case("2f1832d2", "0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xxAj7v1pDL0QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJ2OySqa0q")]
#[tokio::test] #[tokio::test]
#[traced_test] #[traced_test]
async fn sig_tests(#[case] js_hash: &str, #[case] exp_sig: &str) { async fn sig_tests() {
let (js_url, js_path) = player_js_file(js_hash).await; let cases = [
let player_js = std::fs::read_to_string(js_path).unwrap(); ("6ed0d907", "AOq0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xx8j7v1pDL2QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJoOySqa0"),
let deobf_data = DeobfData::extract_fns(&js_url, &player_js).unwrap(); ("3bb1f723", "MyOSJXtKI3m-uME_jv7-pT12gOFC02RFkGoqWpzE0Cs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA"),
let deobf = Deobfuscator::new(&deobf_data).unwrap(); ("2f1832d2", "0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xxAj7v1pDL0QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJ2OySqa0q"),
("643afba4", "AAOAOq0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xx8j7vgpDL0QwbdV06sCIEzpWqMGkFR20CFOS21Tp-7vj_EMu-m37KtXJoOy1"),
("363db69b", "0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpz2ICs6EVdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA"),
("6450230e", "qax0aqSyOoJXtK73m-uME_jv7-pT152OFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8gx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA"),
];
let deobf_sig = deobf.deobfuscate_sig("2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA").unwrap(); for (js_hash, exp_sig) in cases {
assert_eq!(deobf_sig, exp_sig, "js: {js_hash}"); let span = tracing::span!(tracing::Level::ERROR, "sig_test", js_hash);
let _enter = span.enter();
let (js_url, js_path) = player_js_file(js_hash).await;
let player_js = std::fs::read_to_string(js_path).unwrap();
let deobf_data = DeobfData::extract_fns(&js_url, &player_js).unwrap();
let deobf = Deobfuscator::new(&deobf_data).unwrap();
let deobf_sig = deobf.deobfuscate_sig("2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA").unwrap();
assert_eq!(deobf_sig, exp_sig, "[{js_hash}]");
}
} }
#[rstest]
#[case("7862ca1f", "X_LCxVDjAavgE5t", "yxJ1dM6iz5ogUg")]
#[case("9216d1f7", "SLp9F5bwjAdhE9F-", "gWnb9IK2DJ8Q1w")]
#[case("f8cb7a3b", "oBo2h5euWy6osrUt", "ivXHpm7qJjJN")]
#[case("2dfe380c", "oBo2h5euWy6osrUt", "3DIBbn3qdQ")]
#[case("f1ca6900", "cu3wyu6LQn2hse", "jvxetvmlI9AN9Q")]
#[case("8040e515", "wvOFaY-yjgDuIEg5", "HkfBFDHmgw4rsw")]
#[case("e06dea74", "AiuodmaDDYw8d3y4bf", "ankd8eza2T6Qmw")]
#[case("5dd88d1d", "kSxKFLeqzv_ZyHSAt", "n8gS8oRlHOxPFA")]
#[case("324f67b9", "xdftNy7dh9QGnhW", "22qLGxrmX8F1rA")]
#[case("4c3f79c5", "TDCstCG66tEAO5pR9o", "dbxNtZ14c-yWyw")]
#[case("c81bbb4a", "gre3EcLurNY2vqp94", "Z9DfGxWP115WTg")]
#[case("1f7d5369", "batNX7sYqIJdkJ", "IhOkL_zxbkOZBw")]
#[case("009f1d77", "5dwFHw8aFWQUQtffRq", "audescmLUzI3jw")]
#[case("dc0c6770", "5EHDMgYLV6HPGk_Mu-kk", "n9lUJLHbxUI0GQ")]
#[case("113ca41c", "cgYl-tlYkhjT7A", "hI7BBr2zUgcmMg")]
#[case("c57c113c", "M92UUMHa8PdvPd3wyM", "3hPqLJsiNZx7yA")]
#[case("5a3b6271", "B2j7f_UPT4rfje85Lu_e", "m5DmNymaGQ5RdQ")]
#[case("7a062b77", "NRcE3y3mVtm_cV-W", "VbsCYUATvqlt5w")]
#[case("dac945fd", "o8BkRxXhuYsBCWi6RplPdP", "3Lx32v_hmzTm6A")]
#[case("6f20102c", "lE8DhoDmKqnmJJ", "pJTTX6XyJP2BYw")]
#[case("cfa9e7cb", "aCi3iElgd2kq0bxVbQ", "QX1y8jGb2IbZ0w")]
#[case("8c7583ff", "1wWCVpRR96eAmMI87L", "KSkWAVv1ZQxC3A")]
#[case("b7910ca8", "_hXMCwMt9qE310D", "LoZMgkkofRMCZQ")]
#[case("590f65a6", "1tm7-g_A9zsI8_Lay_", "xI4Vem4Put_rOg")]
#[case("b22ef6e7", "b6HcntHGkvBLk_FRf", "kNPW6A7FyP2l8A")]
#[case("3400486c", "lL46g3XifCKUZn1Xfw", "z767lhet6V2Skl")]
#[case("20dfca59", "-fLCxedkAk4LUTK2", "O8kfRq1y1eyHGw")]
#[case("b12cc44b", "keLa5R2U00sR9SQK", "N1OGyujjEwMnLw")]
#[case("3bb1f723", "gK15nzVyaXE9RsMP3z", "ZFFWFLPWx9DEgQ")]
#[case("2f1832d2", "YWt1qdbe8SAfkoPHW5d", "RrRjWQOJmBiP")]
#[case("19d2ae9d", "YWt1qdbe8SAfkoPHW5d", "CS6dVTYzpZrAZ5TD")]
#[tokio::test] #[tokio::test]
#[traced_test] #[traced_test]
async fn nsig_tests(#[case] js_hash: &str, #[case] nsig_in: &str, #[case] expect: &str) { async fn nsig_tests() {
let (js_url, js_path) = player_js_file(js_hash).await; let cases = [
let player_js = std::fs::read_to_string(js_path).unwrap(); ("7862ca1f", "X_LCxVDjAavgE5t", "yxJ1dM6iz5ogUg"),
let deobf_data = DeobfData::extract_fns(&js_url, &player_js).unwrap(); ("9216d1f7", "SLp9F5bwjAdhE9F-", "gWnb9IK2DJ8Q1w"),
let deobf = Deobfuscator::new(&deobf_data).unwrap(); ("f8cb7a3b", "oBo2h5euWy6osrUt", "ivXHpm7qJjJN"),
("2dfe380c", "oBo2h5euWy6osrUt", "3DIBbn3qdQ"),
("f1ca6900", "cu3wyu6LQn2hse", "jvxetvmlI9AN9Q"),
("8040e515", "wvOFaY-yjgDuIEg5", "HkfBFDHmgw4rsw"),
("e06dea74", "AiuodmaDDYw8d3y4bf", "ankd8eza2T6Qmw"),
("5dd88d1d", "kSxKFLeqzv_ZyHSAt", "n8gS8oRlHOxPFA"),
("324f67b9", "xdftNy7dh9QGnhW", "22qLGxrmX8F1rA"),
("4c3f79c5", "TDCstCG66tEAO5pR9o", "dbxNtZ14c-yWyw"),
("c81bbb4a", "gre3EcLurNY2vqp94", "Z9DfGxWP115WTg"),
("1f7d5369", "batNX7sYqIJdkJ", "IhOkL_zxbkOZBw"),
("009f1d77", "5dwFHw8aFWQUQtffRq", "audescmLUzI3jw"),
("dc0c6770", "5EHDMgYLV6HPGk_Mu-kk", "n9lUJLHbxUI0GQ"),
("113ca41c", "cgYl-tlYkhjT7A", "hI7BBr2zUgcmMg"),
("c57c113c", "M92UUMHa8PdvPd3wyM", "3hPqLJsiNZx7yA"),
("5a3b6271", "B2j7f_UPT4rfje85Lu_e", "m5DmNymaGQ5RdQ"),
("7a062b77", "NRcE3y3mVtm_cV-W", "VbsCYUATvqlt5w"),
("dac945fd", "o8BkRxXhuYsBCWi6RplPdP", "3Lx32v_hmzTm6A"),
("6f20102c", "lE8DhoDmKqnmJJ", "pJTTX6XyJP2BYw"),
("cfa9e7cb", "aCi3iElgd2kq0bxVbQ", "QX1y8jGb2IbZ0w"),
("8c7583ff", "1wWCVpRR96eAmMI87L", "KSkWAVv1ZQxC3A"),
("b7910ca8", "_hXMCwMt9qE310D", "LoZMgkkofRMCZQ"),
("590f65a6", "1tm7-g_A9zsI8_Lay_", "xI4Vem4Put_rOg"),
("b22ef6e7", "b6HcntHGkvBLk_FRf", "kNPW6A7FyP2l8A"),
("3400486c", "lL46g3XifCKUZn1Xfw", "z767lhet6V2Skl"),
("20dfca59", "-fLCxedkAk4LUTK2", "O8kfRq1y1eyHGw"),
("b12cc44b", "keLa5R2U00sR9SQK", "N1OGyujjEwMnLw"),
("3bb1f723", "gK15nzVyaXE9RsMP3z", "ZFFWFLPWx9DEgQ"),
("2f1832d2", "YWt1qdbe8SAfkoPHW5d", "RrRjWQOJmBiP"),
("19d2ae9d", "YWt1qdbe8SAfkoPHW5d", "CS6dVTYzpZrAZ5TD"),
("e7567ecf", "Sy4aDGc0VpYRR9ew_", "5UPOT1VhoZxNLQ"),
("d50f54ef", "Ha7507LzRmH3Utygtj", "XFTb2HoeOE5MHg"),
("074a8365", "Ha7507LzRmH3Utygtj", "ufTsrE0IVYrkl8v"),
("643afba4", "N5uAlLqm0eg1GyHO", "dCBQOejdq5s-ww"),
("69f581a5", "-qIP447rVlTTwaZjY", "KNcGOksBAvwqQg"),
("363db69b", "eWYu5d5YeY_4LyEDc", "XJQqf-N7Xra3gg"),
("6450230e", "eWYu5d5YeY_4LyEDc", "VfULHmlBUoDPVMN"),
];
let deobf_nsig = deobf.deobfuscate_nsig(nsig_in).unwrap(); for (js_hash, nsig_in, exp_nsig) in cases {
assert_eq!(deobf_nsig, expect, "js: {js_hash}"); let span = tracing::span!(tracing::Level::ERROR, "nsig_test", js_hash);
let _enter = span.enter();
let (js_url, js_path) = player_js_file(js_hash).await;
let player_js = std::fs::read_to_string(js_path).unwrap();
let deobf_data = DeobfData::extract_fns(&js_url, &player_js).expect(js_hash);
let deobf = Deobfuscator::new(&deobf_data).expect(js_hash);
let deobf_nsig = deobf.deobfuscate_nsig(nsig_in).expect(js_hash);
assert_eq!(deobf_nsig, exp_nsig, "[{js_hash}]");
}
} }
#[tokio::test] #[tokio::test]

View file

@ -105,6 +105,13 @@ pub enum UnavailabilityReason {
OfflineLivestream, OfflineLivestream,
/// YouTube banned your IP address from accessing the platform without an account /// YouTube banned your IP address from accessing the platform without an account
IpBan, IpBan,
/// YouTube bans IP addresses from certain VPN providers from accessing certain geo-restricted
/// videos.
///
/// If this happens to you, you can try another server / VPN provider or disable your VPN.
VpnBan,
/// YouTube requires the user to solve a ReCaptcha
Captcha,
/// Video temporarily unavailable (rate limit) /// Video temporarily unavailable (rate limit)
TryAgain, TryAgain,
/// Video cant be played for other reasons /// Video cant be played for other reasons
@ -125,6 +132,8 @@ impl Display for UnavailabilityReason {
UnavailabilityReason::MembersOnly => f.write_str("members-only"), UnavailabilityReason::MembersOnly => f.write_str("members-only"),
UnavailabilityReason::OfflineLivestream => f.write_str("offline stream"), UnavailabilityReason::OfflineLivestream => f.write_str("offline stream"),
UnavailabilityReason::IpBan => f.write_str("ip-ban"), UnavailabilityReason::IpBan => f.write_str("ip-ban"),
UnavailabilityReason::VpnBan => f.write_str("vpn-ban"),
UnavailabilityReason::Captcha => f.write_str("captcha"),
UnavailabilityReason::TryAgain => f.write_str("try again"), UnavailabilityReason::TryAgain => f.write_str("try again"),
UnavailabilityReason::Unplayable => f.write_str("unplayable"), UnavailabilityReason::Unplayable => f.write_str("unplayable"),
} }
@ -151,6 +160,8 @@ pub enum AuthError {
} }
pub(crate) mod internal { pub(crate) mod internal {
use std::borrow::Cow;
use super::{Error, ExtractionError}; use super::{Error, ExtractionError};
/// Error that occurred during the initialization /// Error that occurred during the initialization
@ -168,7 +179,7 @@ pub(crate) mod internal {
Extraction(&'static str), Extraction(&'static str),
/// Unspecified error /// Unspecified error
#[error("error: {0}")] #[error("error: {0}")]
Other(&'static str), Other(Cow<'static, str>),
} }
impl From<DeobfError> for Error { impl From<DeobfError> for Error {

View file

@ -38,7 +38,7 @@ pub struct Thumbnail {
pub enum UrlTarget { pub enum UrlTarget {
/// YouTube video /// YouTube video
/// ///
/// Example: <youtube.com/watch?v=ZeerrnuLi5E> /// Example: <https://youtube.com/watch?v=ZeerrnuLi5E>
Video { Video {
/// Unique YouTube video ID /// Unique YouTube video ID
id: String, id: String,
@ -1049,6 +1049,8 @@ pub struct TrackItem {
pub track_nr: Option<u16>, pub track_nr: Option<u16>,
/// Is the track by 'Various artists'? /// Is the track by 'Various artists'?
pub by_va: bool, pub by_va: bool,
/// Is the track unavailable on YouTube Music?
pub unavailable: bool,
} }
/// YouTube Music artist list item /// YouTube Music artist list item
@ -1234,6 +1236,8 @@ pub struct MusicAlbum {
pub year: Option<u16>, pub year: Option<u16>,
/// Is the album by 'Various artists'? /// Is the album by 'Various artists'?
pub by_va: bool, pub by_va: bool,
/// Number of album tracks
pub track_count: u16,
/// Album tracks /// Album tracks
pub tracks: Vec<TrackItem>, pub tracks: Vec<TrackItem>,
/// Album variants /// Album variants

View file

@ -70,6 +70,8 @@ pub struct RustyPipeInfo<'a> {
/// YouTube content language /// YouTube content language
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<Language>, pub language: Option<Language>,
/// RustyPipe Botguard version (`rustypipe-botguard 0.1.1`)
pub botguard_version: Option<&'a str>,
} }
/// Reported HTTP request data /// Reported HTTP request data
@ -104,13 +106,14 @@ pub enum Level {
ERR, ERR,
} }
impl RustyPipeInfo<'_> { impl<'a> RustyPipeInfo<'a> {
pub(crate) fn new(language: Option<Language>) -> Self { pub(crate) fn new(language: Option<Language>, botguard_version: Option<&'a str>) -> Self {
Self { Self {
package: env!("CARGO_PKG_NAME"), package: env!("CARGO_PKG_NAME"),
version: crate::VERSION, version: crate::VERSION,
date: util::now_sec(), date: util::now_sec(),
language, language,
botguard_version,
} }
} }
} }

View file

@ -25,7 +25,8 @@ pub fn shift_years(date: Date, years: i32) -> Date {
shift_months(date, years * 12) shift_months(date, years * 12)
} }
pub fn shift_weeks_mo(date: Date, weeks: i32) -> Date { /// Shift a date to the monday of its week, plus/minus the given amount of weeks
pub fn shift_weeks_monday(date: Date, weeks: i32) -> Date {
let d = date + Duration::weeks(weeks.into()); let d = date + Duration::weeks(weeks.into());
Date::from_iso_week_date(d.year(), d.iso_week(), time::Weekday::Monday).unwrap() Date::from_iso_week_date(d.year(), d.iso_week(), time::Weekday::Monday).unwrap()
} }
@ -40,3 +41,18 @@ pub fn now_sec() -> OffsetDateTime {
.replace_nanosecond(0) .replace_nanosecond(0)
.unwrap() .unwrap()
} }
#[cfg(test)]
mod tests {
use rstest::rstest;
use time::{macros::date, Date};
#[rstest]
#[case::this_week(date!(2025-01-17), 0, date!(2025-01-13))]
#[case::last_week(date!(2025-01-17), -1, date!(2025-01-06))]
#[case::last_month(date!(2025-01-17), -4, date!(2024-12-16))]
fn shift_weeks_monday(#[case] date: Date, #[case] weeks: i32, #[case] expect: Date) {
let res = super::shift_weeks_monday(date, weeks);
assert_eq!(res, expect);
}
}

View file

@ -53,6 +53,8 @@ pub(crate) struct Entry {
pub chan_prefix: &'static str, pub chan_prefix: &'static str,
/// Channel name suffix on playlist pages /// Channel name suffix on playlist pages
pub chan_suffix: &'static str, pub chan_suffix: &'static str,
/// "Other versions" title on album pages
pub album_versions_title: &'static str,
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -183,6 +185,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "deur", chan_prefix: "deur",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Ander weergawes",
}, },
Language::Am => Entry { Language::Am => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -310,6 +313,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "", chan_suffix: "",
album_versions_title: "ሌሎች ስሪቶች",
}, },
Language::Ar => Entry { Language::Ar => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -445,6 +449,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "بواسطة", chan_prefix: "بواسطة",
chan_suffix: "", chan_suffix: "",
album_versions_title: "إصدارات أخرى",
}, },
Language::As => Entry { Language::As => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -567,6 +572,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "ৰ দ\u{9cd}\u{9be}\u{9be}", chan_suffix: "ৰ দ\u{9cd}\u{9be}\u{9be}",
album_versions_title: "অন\u{9cd}য সংস\u{9cd}কৰণ",
}, },
Language::Az => Entry { Language::Az => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -682,6 +688,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "by", chan_prefix: "by",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Digər versiyalar",
}, },
Language::Be => Entry { Language::Be => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -829,6 +836,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "ад", chan_prefix: "ад",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Іншыя версіі",
}, },
Language::Bg => Entry { Language::Bg => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -945,6 +953,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "от", chan_prefix: "от",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Други версии",
}, },
Language::Bn => Entry { Language::Bn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1062,6 +1071,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: ",", chan_prefix: ",",
chan_suffix: "\u{9cd}\u{9be}\u{9be}", chan_suffix: "\u{9cd}\u{9be}\u{9be}",
album_versions_title: "অন\u{9cd}য সংস\u{9cd}করণগ\u{9c1}লি",
}, },
Language::Bs => Entry { Language::Bs => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1201,6 +1211,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "od", chan_prefix: "od",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Druge verzije",
}, },
Language::Ca => Entry { Language::Ca => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1325,6 +1336,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de:", chan_prefix: "de:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Altres versions",
}, },
Language::Cs => Entry { Language::Cs => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1455,6 +1467,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "autor:", chan_prefix: "autor:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Jiné verze",
}, },
Language::Da => Entry { Language::Da => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1579,6 +1592,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "af", chan_prefix: "af",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Andre versioner",
}, },
Language::De => Entry { Language::De => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1700,6 +1714,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "von", chan_prefix: "von",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Weitere Versionen",
}, },
Language::El => Entry { Language::El => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1830,6 +1845,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "από το χρήστη", chan_prefix: "από το χρήστη",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Άλλες εκτελέσεις",
}, },
Language::En | Language::EnGb | Language::EnIn => Entry { Language::En | Language::EnGb | Language::EnIn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -1971,6 +1987,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "by", chan_prefix: "by",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Other versions",
}, },
Language::Es => Entry { Language::Es => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2098,6 +2115,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Otras versiones",
}, },
Language::EsUs | Language::Es419 => Entry { Language::EsUs | Language::Es419 => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2226,6 +2244,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Otras versiones",
}, },
Language::Et => Entry { Language::Et => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2351,6 +2370,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "kanalilt", chan_prefix: "kanalilt",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Teised versioonid",
}, },
Language::Eu => Entry { Language::Eu => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2467,6 +2487,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "egilea:", chan_prefix: "egilea:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Beste bertsio batzuk",
}, },
Language::Fa => Entry { Language::Fa => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2574,6 +2595,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "توسط", chan_prefix: "توسط",
chan_suffix: "", chan_suffix: "",
album_versions_title: "نسخه\u{200c}های دیگر",
}, },
Language::Fi => Entry { Language::Fi => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2693,6 +2715,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "tekijä:", chan_prefix: "tekijä:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Muut versiot",
}, },
Language::Fil => Entry { Language::Fil => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2810,6 +2833,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "ni/ng", chan_prefix: "ni/ng",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Iba pang bersyon",
}, },
Language::Fr | Language::FrCa => Entry { Language::Fr | Language::FrCa => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -2941,6 +2965,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Autres versions",
}, },
Language::Gl => Entry { Language::Gl => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3065,6 +3090,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Outras versións",
}, },
Language::Gu => Entry { Language::Gu => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3170,6 +3196,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{acd}વારા", chan_suffix: "\u{acd}વારા",
album_versions_title: "અન\u{acd}ય વર\u{acd}ઝન",
}, },
Language::Hi => Entry { Language::Hi => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3286,6 +3313,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{947}\u{93c}रिए", chan_suffix: "\u{947}\u{93c}रिए",
album_versions_title: "अन\u{94d}य वर\u{94d}शन",
}, },
Language::Hr => Entry { Language::Hr => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3425,6 +3453,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "omogućio kanal", chan_prefix: "omogućio kanal",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Druge verzije",
}, },
Language::Hu => Entry { Language::Hu => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3554,6 +3583,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "csatornától", chan_suffix: "csatornától",
album_versions_title: "Más verziók",
}, },
Language::Hy => Entry { Language::Hy => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3676,6 +3706,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "հեղինակ՝", chan_prefix: "հեղինակ՝",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Այլ տարբերակներ",
}, },
Language::Id => Entry { Language::Id => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3794,6 +3825,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "oleh", chan_prefix: "oleh",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Versi lainnya",
}, },
Language::Is => Entry { Language::Is => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -3928,6 +3960,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "eftir", chan_prefix: "eftir",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Aðrar útgáfur",
}, },
Language::It => Entry { Language::It => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4060,6 +4093,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "di", chan_prefix: "di",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Altre versioni",
}, },
Language::Iw => Entry { Language::Iw => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4198,6 +4232,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "מאת", chan_prefix: "מאת",
chan_suffix: "", chan_suffix: "",
album_versions_title: "גרסאות אחרות",
}, },
Language::Ja => Entry { Language::Ja => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4278,6 +4313,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "作成者:", chan_prefix: "作成者:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "他のバージョン",
}, },
Language::Ka => Entry { Language::Ka => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4400,6 +4436,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "-ის მიერ", chan_suffix: "-ის მიერ",
album_versions_title: "სხვა ვერსიები",
}, },
Language::Kk => Entry { Language::Kk => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4523,6 +4560,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "қосқан", chan_prefix: "қосқан",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Басқа нұсқалары",
}, },
Language::Km => Entry { Language::Km => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4623,6 +4661,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "ដោយ", chan_prefix: "ដោយ",
chan_suffix: "", chan_suffix: "",
album_versions_title: "\u{17d2}រភេទផ\u{17d2}សេងៗ",
}, },
Language::Kn => Entry { Language::Kn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4749,6 +4788,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "ಚಾನಲ\u{ccd}\u{200c}\u{cbf}ಂದ", chan_suffix: "ಚಾನಲ\u{ccd}\u{200c}\u{cbf}ಂದ",
album_versions_title: "ಇತರ ಆವೃತ\u{ccd}\u{cbf}ಗಳು",
}, },
Language::Ko => Entry { Language::Ko => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4832,6 +4872,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "게시자:", chan_prefix: "게시자:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "다른 버전",
}, },
Language::Ky => Entry { Language::Ky => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -4950,6 +4991,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "каналы аркылуу", chan_suffix: "каналы аркылуу",
album_versions_title: "Башка версиялар",
}, },
Language::Lo => Entry { Language::Lo => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5076,6 +5118,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "ໂດຍ", chan_prefix: "ໂດຍ",
chan_suffix: "", chan_suffix: "",
album_versions_title: "ເວ\u{eb5}\u{eb1}ນອ\u{eb7}\u{ec8}ນໆ",
}, },
Language::Lt => Entry { Language::Lt => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5210,6 +5253,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "pridėjo", chan_prefix: "pridėjo",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Kitos versijos",
}, },
Language::Lv => Entry { Language::Lv => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5344,6 +5388,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "autors:", chan_prefix: "autors:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Citas versijas",
}, },
Language::Mk => Entry { Language::Mk => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5471,6 +5516,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "од", chan_prefix: "од",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Други верзии",
}, },
Language::Ml => Entry { Language::Ml => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5585,6 +5631,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{d41}ഖേന", chan_suffix: "\u{d41}ഖേന",
album_versions_title: "മറ\u{d4d}\u{d4d} പതിപ\u{d4d}\u{d41}കൾ",
}, },
Language::Mn => Entry { Language::Mn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5689,6 +5736,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "сувгийн нэр:", chan_prefix: "сувгийн нэр:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Бусад хувилбар",
}, },
Language::Mr => Entry { Language::Mr => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5813,6 +5861,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{94d}वार\u{947}", chan_suffix: "\u{94d}वार\u{947}",
album_versions_title: "इतर आव\u{943}\u{94d}\u{94d}या",
}, },
Language::Ms => Entry { Language::Ms => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -5926,6 +5975,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "oleh", chan_prefix: "oleh",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Versi lain",
}, },
Language::My => Entry { Language::My => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6046,6 +6096,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{103e}", chan_suffix: "\u{103e}",
album_versions_title: "အခြား ဗားရ\u{103e}\u{103a}းများ",
}, },
Language::Ne => Entry { Language::Ne => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6149,6 +6200,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{94d}वारा", chan_suffix: "\u{94d}वारा",
album_versions_title: "अन\u{94d}य स\u{902}\u{94d}करणहर\u{942}",
}, },
Language::Nl => Entry { Language::Nl => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6271,6 +6323,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "door", chan_prefix: "door",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Andere versies",
}, },
Language::No => Entry { Language::No => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6399,6 +6452,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "av", chan_prefix: "av",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Andre versjoner",
}, },
Language::Or => Entry { Language::Or => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6514,6 +6568,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{b4d}\u{b3e}\u{b3e}", chan_suffix: "\u{b4d}\u{b3e}\u{b3e}",
album_versions_title: "ଅନ\u{b4d}ୟ ସଂସ\u{b4d}କରଣଗ\u{b41}\u{b3c}\u{b3f}",
}, },
Language::Pa => Entry { Language::Pa => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6629,6 +6684,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{a71}\u{a4b}\u{a02}", chan_suffix: "\u{a71}\u{a4b}\u{a02}",
album_versions_title: "\u{a4b}ਰ ਵਰਜਨ",
}, },
Language::Pl => Entry { Language::Pl => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6774,6 +6830,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "autor:", chan_prefix: "autor:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Inne wersje",
}, },
Language::Pt => Entry { Language::Pt => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -6903,6 +6960,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "por", chan_prefix: "por",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Outras versões",
}, },
Language::PtPt => Entry { Language::PtPt => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7015,6 +7073,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Outras versões",
}, },
Language::Ro => Entry { Language::Ro => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7143,6 +7202,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "de", chan_prefix: "de",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Alte versiuni",
}, },
Language::Ru => Entry { Language::Ru => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7286,6 +7346,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Другие версии",
}, },
Language::Si => Entry { Language::Si => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7397,6 +7458,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{dd2}\u{dd2}\u{dca}", chan_suffix: "\u{dd2}\u{dd2}\u{dca}",
album_versions_title: "අනෙක\u{dd4}\u{dca} අන\u{dd4}\u{dcf}දයන\u{dca}",
}, },
Language::Sk => Entry { Language::Sk => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7527,6 +7589,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "Autori:", chan_prefix: "Autori:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Ďalšie verzie",
}, },
Language::Sl => Entry { Language::Sl => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7676,6 +7739,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "kanal", chan_prefix: "kanal",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Druge različice",
}, },
Language::Sq => Entry { Language::Sq => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7796,6 +7860,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "nga", chan_prefix: "nga",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Versione të tjera",
}, },
Language::Sr => Entry { Language::Sr => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -7926,6 +7991,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "са канала", chan_prefix: "са канала",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Друге верзије",
}, },
Language::SrLatn => Entry { Language::SrLatn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8056,6 +8122,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "sa kanala", chan_prefix: "sa kanala",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Druge verzije",
}, },
Language::Sv => Entry { Language::Sv => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8178,6 +8245,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "från", chan_prefix: "från",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Andra versioner",
}, },
Language::Sw => Entry { Language::Sw => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8291,6 +8359,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "kutoka", chan_prefix: "kutoka",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Matoleo mengine",
}, },
Language::Ta => Entry { Language::Ta => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8421,6 +8490,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "வழங\u{bcd}கியவர\u{bcd}:", chan_prefix: "வழங\u{bcd}கியவர\u{bcd}:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "பிற பதிப\u{bcd}புகள\u{bcd}",
}, },
Language::Te => Entry { Language::Te => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8547,6 +8617,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "\u{c3e}\u{c46}\u{c4d}\u{c4d}\u{c3e}\u{c3e}", chan_suffix: "\u{c3e}\u{c46}\u{c4d}\u{c4d}\u{c3e}\u{c3e}",
album_versions_title: "ఇతర వ\u{c46}\u{c4d}షన\u{c4d}\u{200c}లు",
}, },
Language::Th => Entry { Language::Th => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8677,6 +8748,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "โดย", chan_prefix: "โดย",
chan_suffix: "", chan_suffix: "",
album_versions_title: "เวอร\u{e4c}\u{e31}นอ\u{e37}\u{e48}นๆ",
}, },
Language::Tr => Entry { Language::Tr => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8797,6 +8869,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "tarafından", chan_suffix: "tarafından",
album_versions_title: "Diğer versiyonlar",
}, },
Language::Uk => Entry { Language::Uk => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -8945,6 +9018,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "власник:", chan_prefix: "власник:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Інші версії",
}, },
Language::Ur => Entry { Language::Ur => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9070,6 +9144,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "منجانب", chan_prefix: "منجانب",
chan_suffix: "", chan_suffix: "",
album_versions_title: "دیگر ورژنز",
}, },
Language::Uz => Entry { Language::Uz => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9184,6 +9259,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "muallif:", chan_prefix: "muallif:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Boshqa versiyalari",
}, },
Language::Vi => Entry { Language::Vi => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9265,6 +9341,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "của", chan_prefix: "của",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Các phiên bản khác",
}, },
Language::ZhCn => Entry { Language::ZhCn => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9362,6 +9439,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "创建者:", chan_prefix: "创建者:",
chan_suffix: "", chan_suffix: "",
album_versions_title: "其他版本",
}, },
Language::ZhHk => Entry { Language::ZhHk => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9443,6 +9521,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "來自", chan_prefix: "來自",
chan_suffix: "", chan_suffix: "",
album_versions_title: "其他版本",
}, },
Language::ZhTw => Entry { Language::ZhTw => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9523,6 +9602,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "", chan_prefix: "",
chan_suffix: "建立", chan_suffix: "建立",
album_versions_title: "其他版本",
}, },
Language::Zu => Entry { Language::Zu => Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
@ -9658,6 +9738,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
}, },
chan_prefix: "ka-", chan_prefix: "ka-",
chan_suffix: "", chan_suffix: "",
album_versions_title: "Ezinye izinguqulo",
}, },
} }
} }

View file

@ -5,7 +5,7 @@ mod visitor_data;
pub mod dictionary; pub mod dictionary;
pub mod timeago; pub mod timeago;
pub use date::{now_sec, shift_months, shift_weeks_mo, shift_years}; pub use date::{now_sec, shift_months, shift_weeks_monday, shift_years};
pub use protobuf::{string_from_pb, ProtoBuilder}; pub use protobuf::{string_from_pb, ProtoBuilder};
pub use visitor_data::VisitorDataCache; pub use visitor_data::VisitorDataCache;
@ -21,7 +21,7 @@ use regex::Regex;
use url::Url; use url::Url;
use crate::{ use crate::{
error::{AuthError, Error, ExtractionError}, error::Error,
param::{Country, Language, COUNTRIES}, param::{Country, Language, COUNTRIES},
serializer::text::TextComponent, serializer::text::TextComponent,
}; };
@ -75,10 +75,10 @@ pub fn get_cg_from_fancy_regexes(regexes: &[&str], text: &str, cg_name: &str) ->
/// Generate a random string with given length and byte charset. /// Generate a random string with given length and byte charset.
fn random_string(charset: &[u8], length: usize) -> String { fn random_string(charset: &[u8], length: usize) -> String {
let mut result = String::with_capacity(length); let mut result = String::with_capacity(length);
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
for _ in 0..length { for _ in 0..length {
result.push(char::from(charset[rng.gen_range(0..charset.len())])); result.push(char::from(charset[rng.random_range(0..charset.len())]));
} }
result result
@ -90,14 +90,14 @@ pub fn generate_content_playback_nonce() -> String {
} }
pub fn random_uuid() -> String { pub fn random_uuid() -> String {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
format!( format!(
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}", "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
rng.gen::<u32>(), rng.random::<u32>(),
rng.gen::<u16>(), rng.random::<u16>(),
rng.gen::<u16>(), rng.random::<u16>(),
rng.gen::<u16>(), rng.random::<u16>(),
rng.gen::<u64>() & 0xffff_ffff_ffff, rng.random::<u64>() & 0xffff_ffff_ffff,
) )
} }
@ -229,7 +229,7 @@ pub fn retry_delay(
backoff_base: u32, backoff_base: u32,
) -> u32 { ) -> u32 {
let unjittered_delay = backoff_base.checked_pow(n_past_retries).unwrap_or(u32::MAX); let unjittered_delay = backoff_base.checked_pow(n_past_retries).unwrap_or(u32::MAX);
let jitter_factor = rand::thread_rng().gen_range(800..1500); let jitter_factor = rand::rng().random_range(800..1500);
let jittered_delay = unjittered_delay let jittered_delay = unjittered_delay
.checked_mul(jitter_factor) .checked_mul(jitter_factor)
.unwrap_or(u32::MAX); .unwrap_or(u32::MAX);
@ -581,9 +581,10 @@ where
/// ///
/// If no user is logged in, YouTube returns a "NotFound" error. This has to be corrected /// If no user is logged in, YouTube returns a "NotFound" error. This has to be corrected
/// into a NoLogin error. /// into a NoLogin error.
#[cfg(feature = "userdata")]
pub fn map_internal_playlist_err(e: Error) -> Error { pub fn map_internal_playlist_err(e: Error) -> Error {
if let Error::Extraction(ExtractionError::NotFound { .. }) = e { if let Error::Extraction(crate::error::ExtractionError::NotFound { .. }) = e {
Error::Auth(AuthError::NoLogin) Error::Auth(crate::error::AuthError::NoLogin)
} else { } else {
e e
} }

Some files were not shown because too many files have changed in this diff Show more