diff --git a/README.md b/README.md index 767680f..6cee334 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,34 @@ -# ![RustyPipe](https://codeberg.org/ThetaDev/rustypipe/raw/branch/main/notes/logo.svg) +# ![RustyPipe](notes/logo.png) -[![Current crates.io version](https://img.shields.io/crates/v/rustypipe.svg)](https://crates.io/crates/rustypipe) -[![License](https://img.shields.io/badge/License-GPL--3-blue.svg?style=flat)](https://opensource.org/licenses/GPL-3.0) +[![License: GPL-3.0-or-later](https://img.shields.io/badge/License-GPL--3.0--or--later-blue.svg?style=flat)](LICENSE) [![Docs](https://img.shields.io/docsrs/rustypipe/latest?style=flat)](https://docs.rs/rustypipe) -[![CI status](https://codeberg.org/ThetaDev/rustypipe/actions/workflows/ci.yaml/badge.svg?style=flat&label=CI)](https://codeberg.org/ThetaDev/rustypipe/actions/?workflow=ci.yaml) RustyPipe is a fully featured Rust client for the public YouTube / YouTube Music API (Innertube), inspired by [NewPipe](https://github.com/TeamNewPipe/NewPipeExtractor). +It lets you fetch videos, streams, playlists, channels, search results, music metadata +and more, without an API key and without the official YouTube SDK. + +> **About this fork** +> +> This is a maintained fork of the upstream +> [RustyPipe by ThetaDev](https://codeberg.org/ThetaDev/rustypipe) (GPL-3.0). +> All credit for the original library goes to the upstream author and contributors. +> +> The fork exists to keep the player pipeline working against YouTube's frequently +> rotating `player.js`. The notable changes (see the `sulkta-sig-port` branch and the +> `*-sulkta` tags) are: +> +> - **Soft-fail signature deobfuscation** — when YouTube ships a `player.js` shape the +> built-in regexes don't recognise, the player path no longer aborts. Only the +> load-bearing signature timestamp is treated as required; the actual sig/nsig +> functions are best-effort and a warning is logged instead of failing the whole call. +> - **iOS-first default client order** — the iOS Innertube path returns pre-signed +> stream URLs (no cipher/throttling params) and needs neither device attestation nor +> signature deobfuscation, so it is the most reliable "just works" default. Android is +> kept in rotation only when BotGuard / PO-token signing is wired up. +> +> If you just want the canonical library, use upstream. If you want the resilience +> patches above, this fork is a drop-in replacement at the same API. ## Features @@ -41,16 +63,15 @@ RustyPipe is a fully featured Rust client for the public YouTube / YouTube Music ## Getting started -The RustyPipe library works as follows: at first you have to instantiate a RustyPipe -client. You can either create it with default options or use the `RustyPipe::builder()` -to customize it. +The RustyPipe library works as follows: first you instantiate a RustyPipe client. You can +either create it with default options or use `RustyPipe::builder()` to customize it. -For fetching data you have to start with a new RustyPipe query object (`rp.query()`). -The query object holds options for an individual query (e.g. content language or -country). You can adjust these options with setter methods. Finally call your query -method to fetch the data you need. +For fetching data you start with a new RustyPipe query object (`rp.query()`). The query +object holds options for an individual query (e.g. content language or country). You can +adjust these options with setter methods. Finally call your query method to fetch the data +you need. -All query methods are async, you need the tokio runtime to execute them. +All query methods are async; you need the tokio runtime to execute them. ```rust ignore let rp = RustyPipe::new(); @@ -64,7 +85,7 @@ Here are a few examples to get you started: ```toml [dependencies] -rustypipe = "0.1.3" +rustypipe = "0.11" tokio = { version = "1.20.0", features = ["macros", "rt-multi-thread"] } ``` @@ -123,21 +144,6 @@ async fn main() { } ``` -**Output:** - -```txt -Name: Homelab -Author: Jeff Geerling -Last update: 2023-05-04 -[cVWF3u-y-Zg] I put a computer in my computer (720s) -[ecdm3oA-QdQ] 6-in-1: Build a 6-node Ceph cluster on this Mini ITX Motherboard (783s) -[xvE4HNJZeIg] Scrapyard Server: Fastest all-SSD NAS! (733s) -[RvnG-ywF6_s] Nanosecond clock sync with a Raspberry Pi (836s) -[R2S2RMNv7OU] I made the Petabyte Raspberry Pi even faster! (572s) -[FG--PtrDmw4] Hiding Macs in my Rack! (515s) -... -``` - ### Get a channel ```rust ignore @@ -166,24 +172,26 @@ async fn main() { } ``` -**Output:** +## Building and testing -```txt -Name: Louis Rossmann -Description: I discuss random things of interest to me. (...) -Subscribers: 1780000 -[qBHgJx_rb8E] Introducing Rossmann senior, a genuine fossil 😃 (122s) -[TmV8eAtXc3s] Am I wrong about CompTIA? (592s) -[CjOJJc1qzdY] How FUTO projects loosen Google's grip on your life! (588s) -[0A10JtkkL9A] a private moment between a man and his kitten (522s) -[zbHq5_1Cd5U] Is Texas mandating auto repair shops use OEM parts? SB1083 analysis & breakdown; tldr, no. (645s) -[6Fv8bd9ICb4] Who owns this? (199s) -... +RustyPipe is a standard Cargo workspace (the library plus the `rustypipe-cli` and +`rustypipe-downloader` companion crates). + +```sh +# Build everything +cargo build --workspace + +# Run the offline unit + snapshot tests (no network access required) +cargo test --workspace + +# Run the fork's end-to-end smoke tests against live YouTube +# (network access required; some clients may be rate-limited from datacenter IPs) +cargo test --test sulkta_smoke -- --nocapture ``` ## Crate features -Some features of RustyPipe are gated behind features to avoid compiling unneeded +Some features of RustyPipe are gated behind Cargo features to avoid compiling unneeded dependencies. - `rss` Fetch a channel's RSS feed, which is faster than fetching the channel page @@ -215,8 +223,7 @@ deserialized or parsed, the original response data along with some request metad written to a JSON file in the folder `rustypipe_reports`, located in RustyPipe's storage directory (current folder by default, `~/.local/share/rustypipe` for the CLI). -When submitting a bug report to the RustyPipe project, you can share this report to help -resolve the issue. +When submitting a bug report, you can share this report to help resolve the issue. RustyPipe reports come in 3 severity levels: @@ -234,12 +241,11 @@ Since August 2024 YouTube requires PO tokens to access streams from web-based cl 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 +Therefore, PO token generation is handled by a separate 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. +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 @@ -248,8 +254,8 @@ age-restricted/private videos and user information. There are 2 supported authen methods: OAuth and cookies. To execute a query with authentication, use the `.authenticated()` query option. This -option is enabled by default for queries that always require authentication like -fetching user data. RustyPipe may automatically use authentication in case a video is +option is enabled by default for queries that always require authentication like fetching +user data. RustyPipe may automatically use authentication in case a video is age-restricted or your IP address is banned by YouTube. If you never want to use authentication, set the `.unauthenticated()` query option. @@ -269,17 +275,30 @@ user has logged in and stores the authentication token in the cache. Authenticating with cookies allows you to use the functionality of the YouTube/YouTube Music Desktop client. You can fetch your subscribed channels, playlists and your music -collection. You can also fetch videos using the Desktop client, including private -videos, as long as you have access to them. +collection. You can also fetch videos using the Desktop client, including private videos, +as long as you have access to them. To authenticate with cookies you have to log into YouTube in a fresh browser session (open Incognito/Private mode). Then extract the cookies from the developer tools or by -using browser plugins like "Get cookies.txt LOCALLY" -([Firefox](https://addons.mozilla.org/de/firefox/addon/get-cookies-txt-locally/)) -([Chromium](https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)). -Close the browser window after extracting the cookies to prevent YouTube from rotating -the cookies. +using a browser extension. Close the browser window after extracting the cookies to +prevent YouTube from rotating the cookies. -You can then add the cookies to your RustyPipe client using the `user_auth_set_cookie` -or `user_auth_set_cookie_txt` function. The cookies are stored in the cache file. To log -out, use the function `user_auth_remove_cookie`. +You can then add the cookies to your RustyPipe client using the `user_auth_set_cookie` or +`user_auth_set_cookie_txt` function. The cookies are stored in the cache file. To log out, +use the function `user_auth_remove_cookie`. + +## Contributing + +Issues and pull requests are welcome. Please keep changes focused, run +`cargo fmt`, `cargo clippy --workspace` and `cargo test --workspace` before submitting, +and include a snapshot/unit test for any new parsing behaviour. If your change concerns +the player or signature pipeline, the live smoke tests (`cargo test --test sulkta_smoke`) +are a useful sanity check. + +## License + +RustyPipe is licensed under the **GNU General Public License v3.0 or later** +(GPL-3.0-or-later). See [LICENSE](LICENSE) for the full text. As a fork of the upstream +RustyPipe project, this repository preserves the original license and attribution. + +This project is not affiliated with, sponsored by, or endorsed by YouTube or Google.