From 91e136055cb3ab17407e00f92997a52b591220ce Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Fri, 31 Jul 2026 21:54:15 +0300 Subject: [PATCH] Add the YouTube submission path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 5. A URL goes through the same pipeline as an upload — it just gains a download step and a source_url. - The host allowlist is checked on the parsed hostname before yt-dlp is invoked, so lookalikes and userinfo tricks are refused too - yt-dlp -J reads metadata synchronously with a 15s timeout; a timeout leaves the fields blank rather than failing the submission - Over-long tracks are refused from that metadata, before a byte is downloaded - Failed URL submissions offer Yritä uudelleen with the typed text intact; uploads cannot retry, so they offer re-upload Prefill takes track then title, and artist then creator then uploader, and leaves a field blank rather than inventing one. testdata/ytdlp-noose.json is a real dump of an ordinary upload, which has none of the music fields. Also fixes a URL-only submit being blocked by the file input's required attribute — HTML cannot express "one of these two", so the server says it. The image now takes yt-dlp from Alpine 3.24 instead of pip, which drops python3 and pip entirely; see decision 19. --- Dockerfile | 10 ++-- README.md | 4 +- docs/decisions.md | 8 ++- docs/spec.md | 4 +- main.go | 1 + media.go | 81 ++++++++++++++++++++++++++++ media_test.go | 81 ++++++++++++++++++++++++++++ static/style.css | 3 ++ submit.go | 110 +++++++++++++++++++++++++++++++++++++- templates/submission.html | 14 +++-- templates/submit.html | 6 ++- testdata/ytdlp-noose.json | 1 + 12 files changed, 307 insertions(+), 16 deletions(-) create mode 100644 media_test.go create mode 100644 testdata/ytdlp-noose.json diff --git a/Dockerfile b/Dockerfile index 3017947..84566a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ -FROM golang:1.24-alpine AS build +FROM golang:1.26-alpine AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /levyraati . -FROM alpine:3.21 -# yt-dlp rots against YouTube, so it is installed unpinned at build time and updated by rebuilding. -RUN apk add --no-cache ffmpeg python3 py3-pip ca-certificates \ - && pip install --break-system-packages --no-cache-dir -U yt-dlp +FROM alpine:3.24 +# yt-dlp rots against YouTube. Alpine's active branch tracks it closely (3.24 carries the current +# release), so a rebuild is the update — and this avoids python3 + pip in the image entirely. +RUN apk add --no-cache ffmpeg yt-dlp ca-certificates COPY --from=build /levyraati /usr/local/bin/levyraati ENV STORAGE_DIR=/storage EXPOSE 8080 diff --git a/README.md b/README.md index eaa8360..470266b 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,8 @@ endpoint and no recovery key — the credentials are the environment. ### yt-dlp goes stale -yt-dlp needs regular updates to keep working against YouTube. It is installed with -`pip install -U yt-dlp` at image build time, so rebuilding is how you update it: +yt-dlp needs regular updates to keep working against YouTube. It comes from Alpine's community +repository, whose active branch tracks upstream closely, so rebuilding is how you update it: ```sh docker compose build --no-cache app && docker compose up -d app diff --git a/docs/decisions.md b/docs/decisions.md index a156ff2..93c1175 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -66,8 +66,12 @@ and `storage` was test data, so **the schema has no legacy to respect.** 18. **The issue reporter ships in v1.** One table and two handlers, and the month it is most needed is the first one. Members never touch the Gitea tracker; the admin transcribes anything worth tracking. -19. **yt-dlp: `pip install -U yt-dlp` at image build, rebuild monthly.** Pinning only schedules the - breakage for a moment you did not choose. +19. **yt-dlp is updated by rebuilding the image, monthly.** Pinning a version only schedules the + breakage for a moment you did not choose. Originally `pip install -U yt-dlp`; changed on + 2026-07-31 to `apk add yt-dlp` once Alpine 3.24 turned out to carry the current release + (2026.07.04, four weeks old) — which drops python3 and pip from the image entirely. The apk + route inherits Alpine's packaging lag, so pip is the fallback if it ever goes stale at a bad + moment. Note that this only holds on the *active* branch: 3.21 was 16 months behind. 20. **Parity plus YouTube, then iterate.** Nothing from the old `docs/IDEAS.md` and nothing from the unbuilt-stats list ships in v1. diff --git a/docs/spec.md b/docs/spec.md index 1411123..f5dee5f 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -288,7 +288,9 @@ but its submitter, so a broken pipeline has no other way of announcing itself. ### 4.7 Operational notes -- **yt-dlp rots.** `pip install -U yt-dlp` at image build; rebuild monthly. +- **yt-dlp rots.** Installed with `apk add yt-dlp` from Alpine's active branch, which tracks + upstream closely; rebuild monthly. If the packaged version ever lags at a bad moment, + `pip install -U yt-dlp` is the fallback — at the cost of python3 and pip in the image. - Downloading YouTube audio is against YouTube's ToS. This is a private app among friends; the decision is deliberate rather than accidental. diff --git a/main.go b/main.go index bd80553..adaa6d8 100644 --- a/main.go +++ b/main.go @@ -152,6 +152,7 @@ func (a *app) memberMux() *http.ServeMux { mux.HandleFunc("GET /submit/{id}/status", a.requireMember(a.submissionStatus)) mux.HandleFunc("POST /submit/{id}", a.requireMember(a.saveSubmission)) mux.HandleFunc("POST /submit/{id}/publish", a.requireMember(a.publish)) + mux.HandleFunc("POST /submit/{id}/retry", a.requireMember(a.retry)) mux.HandleFunc("POST /submit/{id}/discard", a.requireMember(a.discard)) return mux } diff --git a/media.go b/media.go index 0d0ce7f..a89000e 100644 --- a/media.go +++ b/media.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + "net/url" "os/exec" "strconv" "strings" @@ -95,6 +96,86 @@ func clean(s string, max int) string { return s } +// Hosts yt-dlp is allowed to see. Validated before the URL goes anywhere near a subprocess +// argument list — and it never goes through a shell. +var allowedHosts = map[string]bool{ + "youtube.com": true, "www.youtube.com": true, "m.youtube.com": true, + "youtu.be": true, "www.youtu.be": true, "music.youtube.com": true, +} + +func allowedYouTubeURL(raw string) (string, bool) { + u, err := url.Parse(strings.TrimSpace(raw)) + if err != nil || (u.Scheme != "http" && u.Scheme != "https") { + return "", false + } + if !allowedHosts[strings.ToLower(u.Hostname())] { + return "", false + } + return u.String(), true +} + +type ytOutput struct { + Title string `json:"title"` + Track string `json:"track"` + Artist string `json:"artist"` + Creator string `json:"creator"` + Uploader string `json:"uploader"` + Duration float64 `json:"duration"` +} + +// youtubeMeta asks yt-dlp for metadata only — no download. A 1–3 s network call, so the handler +// gives it 15 s and renders blank fields on timeout rather than failing the submission. +func youtubeMeta(ctx context.Context, url string) (probeResult, error) { + ctx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + + out, err := exec.CommandContext(ctx, "yt-dlp", "-J", "--no-playlist", "--no-warnings", url).Output() + if err != nil { + return probeResult{}, err + } + return parseYouTubeMeta(out) +} + +// track/artist exist only for Topic channels, YouTube Music entries and videos with a "Music in +// this video" panel. An ordinary upload gives a title and an uploader and nothing else — and if a +// field resolves to empty it stays empty, because a blank field prompts the submitter while a +// plausible "Unknown" does not. +func parseYouTubeMeta(jsonBytes []byte) (probeResult, error) { + var y ytOutput + if err := json.Unmarshal(jsonBytes, &y); err != nil { + return probeResult{}, err + } + title := y.Track + if title == "" { + title = y.Title + } + artist := firstOf(map[string]string{ + "artist": y.Artist, "creator": y.Creator, "uploader": y.Uploader, + }, "artist", "creator", "uploader") + return probeResult{ + Title: clean(title, 100), + Artist: clean(artist, 100), + Duration: time.Duration(y.Duration * float64(time.Second)), + }, nil +} + +// download fetches the best audio-only stream. The extension is whatever YouTube served, so the +// caller globs for it — ffmpeg does not care which container it gets. +func downloadYouTube(ctx context.Context, url, outTemplate string) (string, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) + defer cancel() + + cmd := exec.CommandContext(ctx, "yt-dlp", + "-f", "bestaudio", "--no-playlist", "--max-filesize", "100M", + "--no-warnings", "-o", outTemplate, url) + var stderr strings.Builder + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return tail(stderr.String(), 400), err + } + return "", nil +} + // convertToOpus is also the validation: if ffmpeg produced an Opus stream, the upload was audio. // No container sniffing, no magic-byte library. Returns the stderr tail on failure, which is worth // showing — "Invalid data found when processing input" beats "submission failed". diff --git a/media_test.go b/media_test.go new file mode 100644 index 0000000..bf7c7d7 --- /dev/null +++ b/media_test.go @@ -0,0 +1,81 @@ +package main + +import ( + "os" + "testing" + "time" +) + +func TestAllowedYouTubeURL(t *testing.T) { + for _, ok := range []string{ + "https://www.youtube.com/watch?v=XnfMBo4IQ-g", + "https://youtu.be/XnfMBo4IQ-g", + "https://music.youtube.com/watch?v=XnfMBo4IQ-g", + "http://m.youtube.com/watch?v=XnfMBo4IQ-g", + } { + if _, allowed := allowedYouTubeURL(ok); !allowed { + t.Errorf("%q was rejected", ok) + } + } + for _, bad := range []string{ + "", + "not a url", + "file:///etc/passwd", + "https://evil.example.com/watch?v=x", + // The allowlist is on the host, so a lookalike path or userinfo must not pass. + "https://evil.example.com/www.youtube.com/watch?v=x", + "https://youtube.com.evil.example.com/watch?v=x", + "https://www.youtube.com@evil.example.com/", + "-oExecuteMe", + } { + if _, allowed := allowedYouTubeURL(bad); allowed { + t.Errorf("%q was allowed", bad) + } + } +} + +// A real dump of an ordinary upload: no track, no artist, no creator, no album — just a title with +// double spaces and an uploader. This is why prefill must never invent an "Unknown". +func TestYouTubeMetaFromOrdinaryUpload(t *testing.T) { + raw, err := os.ReadFile("testdata/ytdlp-noose.json") + if err != nil { + t.Skipf("fixture missing: %v", err) + } + meta, err := parseYouTubeMeta(raw) + if err != nil { + t.Fatal(err) + } + if meta.Title != "Sentenced Noose" { + t.Errorf("title = %q, want the cleaned video title", meta.Title) + } + if meta.Artist != "Heikki Rokkonen" { + t.Errorf("artist = %q, want the uploader as the last fallback", meta.Artist) + } + if meta.Duration != 245*time.Second { + t.Errorf("duration = %v, want 4m5s", meta.Duration) + } +} + +func TestYouTubeMetaPrefersMusicFields(t *testing.T) { + meta, err := parseYouTubeMeta([]byte(`{ + "title": "Sentenced - Noose (Official Video)", + "track": "Noose", "artist": "Sentenced", "creator": "ignored", + "uploader": "SentencedVEVO", "duration": 245.0}`)) + if err != nil { + t.Fatal(err) + } + if meta.Title != "Noose" || meta.Artist != "Sentenced" { + t.Errorf("got %q by %q, want the track/artist fields to win", meta.Title, meta.Artist) + } +} + +// Empty stays empty: a blank field prompts the submitter, a plausible "Unknown" does not. +func TestYouTubeMetaLeavesBlanksBlank(t *testing.T) { + meta, err := parseYouTubeMeta([]byte(`{"duration": 10.0}`)) + if err != nil { + t.Fatal(err) + } + if meta.Title != "" || meta.Artist != "" { + t.Errorf("got %q by %q, want both empty", meta.Title, meta.Artist) + } +} diff --git a/static/style.css b/static/style.css index a70411c..b4d52dc 100644 --- a/static/style.css +++ b/static/style.css @@ -228,3 +228,6 @@ button.danger:hover { background: #e53935; } padding: 0.8rem 1rem; margin-bottom: 1.2rem; } .status p { margin: 0 0 0.5rem; } button:disabled { background: var(--surface-2); color: var(--muted); cursor: not-allowed; } + +.or { text-align: center; color: var(--muted); text-transform: uppercase; + font-family: var(--font-head); margin: 0; } diff --git a/submit.go b/submit.go index 1bfe8d7..fc06b30 100644 --- a/submit.go +++ b/submit.go @@ -110,6 +110,9 @@ func (s *submission) Label() string { func (s *submission) Genres() []genre { return genres } +// Only URL submissions can retry: an upload's temp file is gone, so that case offers re-upload. +func (s *submission) CanRetry() bool { return s.Failed() && s.SourceURL != nil } + // The chosen genre's Finnish label, for pages that show it rather than offer it. func (s *submission) GenreLabel() string { return genreLabel(s.Genre) } @@ -169,8 +172,21 @@ func (a *app) submit(w http.ResponseWriter, r *http.Request) { return } + // A YouTube song is not a different kind of song — it just has an extra download step and a + // source_url. Both paths converge on the same worker. + if raw := r.FormValue("url"); strings.TrimSpace(raw) != "" { + a.submitURL(w, r, m.ID, raw) + return + } + r.Body = http.MaxBytesReader(w, r.Body, maxUploadBytes) file, header, err := r.FormFile("audio") + if errors.Is(err, http.ErrMissingFile) { + // Neither field filled. HTML cannot express "one of these two", so the server says it. + a.submitError(w, r, http.StatusUnprocessableEntity, + "Valitse äänitiedosto tai anna YouTube-linkki.") + return + } if err != nil { a.submitError(w, r, http.StatusRequestEntityTooLarge, "Tiedostoa ei voitu lukea. Enintään 50 MB.") @@ -226,10 +242,68 @@ func (a *app) submit(w http.ResponseWriter, r *http.Request) { } slog.Info("submission received", "ctx", "submissions", "submission", subID, "user", m.ID) - go a.convert(subID, src) + go a.process(subID, "", src) http.Redirect(w, r, fmt.Sprintf("/submit/%d", subID), http.StatusSeeOther) } +func (a *app) submitURL(w http.ResponseWriter, r *http.Request, userID int64, raw string) { + // The allowlist is checked before yt-dlp is invoked at all. + link, ok := allowedYouTubeURL(raw) + if !ok { + a.submitError(w, r, http.StatusUnprocessableEntity, + "Vain YouTube-linkit kelpaavat (youtube.com, youtu.be, music.youtube.com).") + return + } + + // Metadata first, so an over-long track is refused before a byte is downloaded. A timeout is + // not fatal: blank fields are a fine outcome, since the submitter fills them in anyway. + meta, err := youtubeMeta(r.Context(), link) + if err != nil { + slog.Warn("yt-dlp metadata", "ctx", "submissions", "error", err) + } + if meta.Duration > maxDuration { + a.submitError(w, r, http.StatusUnprocessableEntity, "Kappale on yli 15 minuuttia pitkä.") + return + } + + var subID int64 + err = a.pool.QueryRow(r.Context(), ` + insert into submissions (user_id, status, source_url, title, artist) + values ($1, 'queued', $2, nullif($3, ''), nullif($4, '')) returning id`, + userID, link, meta.Title, meta.Artist).Scan(&subID) + if err != nil { + slog.Error("create submission", "ctx", "submissions", "error", err) + a.submitError(w, r, http.StatusInternalServerError, "Jokin meni pieleen.") + return + } + + slog.Info("url submission received", "ctx", "submissions", "submission", subID, "user", userID) + go a.process(subID, link, "") + http.Redirect(w, r, fmt.Sprintf("/submit/%d", subID), http.StatusSeeOther) +} + +// Retry re-queues a failed URL submission with the typed title and introduction intact. An upload +// cannot retry — its temp file is gone — so that case offers re-upload instead. +func (a *app) retry(w http.ResponseWriter, r *http.Request) { + s := a.loadSubmission(w, r) + if s == nil { + return + } + if !s.CanRetry() { + http.Error(w, "ei uudelleenyritettävissä", http.StatusConflict) + return + } + if _, err := a.pool.Exec(r.Context(), + `update submissions set status = 'queued', status_msg = null where id = $1`, s.ID); err != nil { + slog.Error("retry", "ctx", "submissions", "error", err, "submission", s.ID) + http.Error(w, "virhe", http.StatusInternalServerError) + return + } + slog.Info("submission retried", "ctx", "submissions", "submission", s.ID) + go a.process(s.ID, *s.SourceURL, "") + http.Redirect(w, r, fmt.Sprintf("/submit/%d", s.ID), http.StatusSeeOther) +} + func (a *app) discardSubmission(ctx context.Context, subID int64, path string) { if path != "" { os.Remove(path) @@ -241,12 +315,44 @@ func (a *app) discardSubmission(ctx context.Context, subID int64, path string) { // --- convert --- -func (a *app) convert(subID int64, src string) { +// process is the whole background half of the pipeline: download when the source is a URL, then +// convert. Everything past the two slots waits in `queued`. +func (a *app) process(subID int64, sourceURL, src string) { slots <- struct{}{} defer func() { <-slots }() // Detached from the request: the submitter's browser is long gone by now. ctx := context.Background() + + if sourceURL != "" { + a.setStatus(ctx, subID, "downloading", "") + msg, err := downloadYouTube(ctx, sourceURL, a.tmpPath(subID, ".%(ext)s")) + if err != nil { + if msg == "" { + msg = err.Error() + } + a.setStatus(ctx, subID, "failed", msg) + slog.Warn("download failed", "ctx", "submissions", "submission", subID, "error", err) + return + } + // yt-dlp names the file after whatever container YouTube served. + matches, _ := filepath.Glob(a.tmpPath(subID, ".*")) + for _, m := range matches { + if filepath.Ext(m) != ".ogg" { + src = m + break + } + } + if src == "" { + a.setStatus(ctx, subID, "failed", "lataus ei tuottanut tiedostoa") + return + } + if _, err := a.pool.Exec(ctx, + `update submissions set tmp_path = $2 where id = $1`, subID, src); err != nil { + slog.Error("save tmp path", "ctx", "submissions", "error", err, "submission", subID) + } + } + a.setStatus(ctx, subID, "converting", "") out := a.tmpPath(subID, ".ogg") diff --git a/templates/submission.html b/templates/submission.html index 559f978..2f854a3 100644 --- a/templates/submission.html +++ b/templates/submission.html @@ -3,9 +3,17 @@

{{.Label}}

{{if .Failed}} {{with .StatusMsg}}

{{.}}

{{end}} -
- -
+
+ {{if .CanRetry}} +
+ +
+ {{end}} +
+ +
+
+ {{if not .CanRetry}}

Lataa tiedosto uudelleen, jos haluat yrittää toisen kerran.

{{end}} {{else}} diff --git a/templates/submit.html b/templates/submit.html index b39d938..7754143 100644 --- a/templates/submit.html +++ b/templates/submit.html @@ -5,11 +5,15 @@
+

tai

+
diff --git a/testdata/ytdlp-noose.json b/testdata/ytdlp-noose.json new file mode 100644 index 0000000..1c191c0 --- /dev/null +++ b/testdata/ytdlp-noose.json @@ -0,0 +1 @@ +{"id": "XnfMBo4IQ-g", "title": "Sentenced Noose", "formats": [{"format_id": "sb2", "format_note": "storyboard", "ext": "mhtml", "protocol": "mhtml", "acodec": "none", "vcodec": "none", "url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L0/default.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCcvbxx0XQPFyOZuYDBxCyFFnGJaw", "width": 48, "height": 27, "fps": 0.40816326530612246, "rows": 10, "columns": 10, "fragments": [{"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L0/default.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCcvbxx0XQPFyOZuYDBxCyFFnGJaw", "duration": 245.0}], "audio_ext": "none", "video_ext": "none", "vbr": 0, "abr": 0, "tbr": null, "resolution": "48x27", "aspect_ratio": 1.78, "filesize_approx": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "sb2 - 48x27 (storyboard)"}, {"format_id": "sb1", "format_note": "storyboard", "ext": "mhtml", "protocol": "mhtml", "acodec": "none", "vcodec": "none", "url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L1/M$M.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCBcW44ydBNg6PDEt4-gtXUzPieNA", "width": 80, "height": 45, "fps": 0.5061224489795918, "rows": 10, "columns": 10, "fragments": [{"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L1/M0.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCBcW44ydBNg6PDEt4-gtXUzPieNA", "duration": 197.58064516129033}, {"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L1/M1.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCBcW44ydBNg6PDEt4-gtXUzPieNA", "duration": 47.419354838709666}], "audio_ext": "none", "video_ext": "none", "vbr": 0, "abr": 0, "tbr": null, "resolution": "80x45", "aspect_ratio": 1.78, "filesize_approx": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "sb1 - 80x45 (storyboard)"}, {"format_id": "sb0", "format_note": "storyboard", "ext": "mhtml", "protocol": "mhtml", "acodec": "none", "vcodec": "none", "url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M$M.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "width": 160, "height": 90, "fps": 0.5061224489795918, "rows": 5, "columns": 5, "fragments": [{"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M0.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "duration": 49.395161290322584}, {"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M1.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "duration": 49.395161290322584}, {"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M2.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "duration": 49.395161290322584}, {"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M3.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "duration": 49.395161290322584}, {"url": "https://i.ytimg.com/sb/XnfMBo4IQ-g/storyboard3_L2/M4.jpg?sqp=-oaymwGhAUg48quKqQOYAYgBAZUBAAAEQpgBMqABPKgBBLIBQBANDBAVHyYtDg4PEhcrLCkPDhAVHyoyKQ8RFBgmPTgtERQeKjFLRzYVHCkuOUdNPyUuNz1HUlFFM0BCQ0xERkO6AUARERUjRENDQxETFi9DQ0NDFRYpQ0NDQ0MjL0NDQ0NDQ0RDQ0NDQ0JCQ0NDQ0NCQkJDQ0NDQkJCQkNDQ0JCQkJCovOX_wMGCNbdu8wF&sigh=rs$AOn4CLCdSOPNcLvnP4aMOmNDYzDw_-joSw", "duration": 47.419354838709666}], "audio_ext": "none", "video_ext": "none", "vbr": 0, "abr": 0, "tbr": null, "resolution": "160x90", "aspect_ratio": 1.78, "filesize_approx": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "sb0 - 160x90 (storyboard)"}, {"asr": 22050, "filesize": 1495626, "format_id": "139", "format_note": "low", "source_preference": -1, "fps": null, "audio_channels": 2, "height": null, "quality": 2.0, "has_drm": false, "tbr": 48.805, "filesize_approx": 1495604, "width": null, "language": null, "language_preference": -1, "preference": null, "ext": "m4a", "vcodec": "none", "acodec": "mp4a.40.5", "dynamic_range": null, "container": "m4a_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=139&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=audio%2Fmp4&rqh=1&gir=yes&clen=1495626&dur=245.156&lmt=1634500644767690&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRAIgHbhds1MamyokcXatw81vLEXWd7hcCjA0nzmeck9mcfICIApTbMdMlBbGytkNq5OSxwy-dn-fXTpUfRE9xsklmwwp&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "audio_ext": "m4a", "video_ext": "none", "vbr": 0, "abr": 48.805, "resolution": "audio only", "aspect_ratio": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "139 - audio only (low)"}, {"asr": 44100, "filesize": 3966794, "format_id": "140", "format_note": "medium", "source_preference": -1, "fps": null, "audio_channels": 2, "height": null, "quality": 3.0, "has_drm": false, "tbr": 129.494, "filesize_approx": 3966773, "width": null, "language": null, "language_preference": -1, "preference": null, "ext": "m4a", "vcodec": "none", "acodec": "mp4a.40.2", "dynamic_range": null, "container": "m4a_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=140&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=audio%2Fmp4&rqh=1&gir=yes&clen=3966794&dur=245.063&lmt=1634500640205796&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgcOfCrKpvix2B38glvH9EBZ0HtCbnAMbwuQgbY68QfiMCIQDsTl4kq_WpisFUQdWoXA_3V_aAUwuuLQlhpJLBQIeB6w%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "audio_ext": "m4a", "video_ext": "none", "vbr": 0, "abr": 129.494, "resolution": "audio only", "aspect_ratio": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "140 - audio only (medium)"}, {"asr": 48000, "filesize": 3804783, "format_id": "251", "format_note": "medium", "source_preference": -1, "fps": null, "audio_channels": 2, "height": null, "quality": 3.0, "has_drm": false, "tbr": 124.227, "filesize_approx": 3804777, "width": null, "language": null, "language_preference": -1, "preference": null, "ext": "webm", "vcodec": "none", "acodec": "opus", "dynamic_range": null, "container": "webm_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=251&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=audio%2Fwebm&rqh=1&gir=yes&clen=3804783&dur=245.021&lmt=1744051873395760&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=8208224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgMpOgu2rpc7C8EK2vhVaj5JHJ05A9E_HB-XYQ5GpGPBgCIQCIGSKoZ4uTYxU6NiSmxbc8YhqN_dMvNV0-IjJca-Qipg%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "audio_ext": "webm", "video_ext": "none", "vbr": 0, "abr": 124.227, "resolution": "audio only", "aspect_ratio": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "251 - audio only (medium)"}, {"asr": null, "filesize": 362998, "format_id": "160", "format_note": "144p", "source_preference": -1, "fps": 30, "audio_channels": null, "height": 144, "quality": 0.0, "has_drm": false, "tbr": 11.852, "filesize_approx": 362983, "width": 256, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.4d400c", "acodec": "none", "dynamic_range": "SDR", "container": "mp4_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=160&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=362998&dur=245.011&lmt=1634500664939803&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgICum4HxK7x00l-FJIS5PTChZW0w-s27pk4tm_5_vzRACIQDJm9eMnrEpjvuethvesmhvvYKp4a8sU8_HTvPVbAKo0A%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "abr": 0, "vbr": 11.852, "resolution": "256x144", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "160 - 256x144 (144p)"}, {"asr": null, "filesize": 870591, "format_id": "134", "format_note": "360p", "source_preference": -1, "fps": 30, "audio_channels": null, "height": 360, "quality": 6.0, "has_drm": false, "tbr": 28.426, "filesize_approx": 870585, "width": 640, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.4d401e", "acodec": "none", "dynamic_range": "SDR", "container": "mp4_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=134&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=870591&dur=245.011&lmt=1634500664937589&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRgIhALPzCMoR_MfIcUSz9WFjfuZB6Wr9ahmq-pcmiaRYJW16AiEA44j7ucA9oqFDVsKfDdneZPwoFRVxt3KKSdI_woAFVIE%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "abr": 0, "vbr": 28.426, "resolution": "640x360", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "134 - 640x360 (360p)"}, {"asr": 44100, "filesize": null, "format_id": "18", "format_note": "360p", "source_preference": -1, "fps": 30, "audio_channels": 2, "height": 360, "quality": 6.0, "has_drm": false, "tbr": 157.199, "filesize_approx": 4815457, "width": 640, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.42001E", "acodec": "mp4a.40.2", "dynamic_range": "SDR", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=18&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhPq5vyWkaxxbGu_I4Y3blOrzDsFs10LN6Ap5zR3b-p-7S7EU9jXKD8AhsLLf4cJll-8CxPapwYR&spc=KBGBchwrn0RDKJhUyrPaoyAxrSqoAoONQkKCIXQznNTTG12b8fIT&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&cnr=14&ratebypass=yes&dur=245.063&lmt=1637768278543009&mt=1785522571&fvip=1&fexp=51565116&c=ANDROID_VR&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Ccnr%2Cratebypass%2Cdur%2Clmt&sig=AE0s2JYwRgIhAMy_BC2FK_uZGyMqoD7CHEgpgQYQ1svb8NC9lDfLSj2TAiEAietjhEhShE-cwR7xvvs_neYfwq6QGrygI6QLiQukxn8%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "vbr": null, "abr": null, "resolution": "640x360", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "18 - 640x360 (360p)"}, {"asr": null, "filesize": 1562387, "format_id": "135", "format_note": "480p", "source_preference": -1, "fps": 30, "audio_channels": null, "height": 480, "quality": 7.0, "has_drm": false, "tbr": 51.014, "filesize_approx": 1562373, "width": 854, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.4d401f", "acodec": "none", "dynamic_range": "SDR", "container": "mp4_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=135&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=1562387&dur=245.011&lmt=1634500664956409&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgSrYBPX9JmxAE1w8sfoj9S3Nl0qRZ1S06oRfbd1Gl6vgCIQCiKhA9G8AwbeRDtR4O_KYNRFqlJZ98ym8ae6RgFeURVA%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "abr": 0, "vbr": 51.014, "resolution": "854x480", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "135 - 854x480 (480p)"}], "thumbnails": [{"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/3.jpg", "preference": -37, "id": "0"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/3.webp", "preference": -36, "id": "1"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/2.jpg", "preference": -35, "id": "2"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/2.webp", "preference": -34, "id": "3"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/1.jpg", "preference": -33, "id": "4"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/1.webp", "preference": -32, "id": "5"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/mq3.jpg", "preference": -31, "id": "6"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/mq3.webp", "preference": -30, "id": "7"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/mq2.jpg", "preference": -29, "id": "8"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/mq2.webp", "preference": -28, "id": "9"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/mq1.jpg", "preference": -27, "id": "10"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/mq1.webp", "preference": -26, "id": "11"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hq3.jpg", "preference": -25, "id": "12"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/hq3.webp", "preference": -24, "id": "13"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hq2.jpg", "preference": -23, "id": "14"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/hq2.webp", "preference": -22, "id": "15"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hq1.jpg", "preference": -21, "id": "16"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/hq1.webp", "preference": -20, "id": "17"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/sd3.jpg", "preference": -19, "id": "18"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/sd3.webp", "preference": -18, "id": "19"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/sd2.jpg", "preference": -17, "id": "20"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/sd2.webp", "preference": -16, "id": "21"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/sd1.jpg", "preference": -15, "id": "22"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/sd1.webp", "preference": -14, "id": "23"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/default.jpg", "height": 90, "width": 120, "preference": -13, "id": "24", "resolution": "120x90"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/default.webp", "preference": -12, "id": "25"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/mqdefault.jpg", "height": 180, "width": 320, "preference": -11, "id": "26", "resolution": "320x180"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/mqdefault.webp", "preference": -10, "id": "27"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/0.jpg", "preference": -9, "id": "28"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/0.webp", "preference": -8, "id": "29"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hqdefault.jpg?sqp=-oaymwEiCKgBEF5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLCOWwlUxy4E51uVcQSSANvptuZlpA", "height": 94, "width": 168, "preference": -7, "id": "30", "resolution": "168x94"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hqdefault.jpg?sqp=-oaymwEiCMQBEG5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLCNiT-GNdS8l-hEc7wRItsvO0vxYg", "height": 110, "width": 196, "preference": -7, "id": "31", "resolution": "196x110"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hqdefault.jpg?sqp=-oaymwEjCPYBEIoBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLC3__3ooDk54Hhev53WSGhMhHRS1A", "height": 138, "width": 246, "preference": -7, "id": "32", "resolution": "246x138"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hqdefault.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLBbXFT7ms833GJSU5tAUXFEYsAQNQ", "height": 188, "width": 336, "preference": -7, "id": "33", "resolution": "336x188"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hqdefault.jpg", "height": 360, "width": 480, "preference": -7, "id": "34", "resolution": "480x360"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/hqdefault.webp", "preference": -6, "id": "35"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/sddefault.jpg", "height": 480, "width": 640, "preference": -5, "id": "36", "resolution": "640x480"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/sddefault.webp", "preference": -4, "id": "37"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/hq720.jpg", "preference": -3, "id": "38"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/hq720.webp", "preference": -2, "id": "39"}, {"url": "https://i.ytimg.com/vi/XnfMBo4IQ-g/maxresdefault.jpg", "preference": -1, "id": "40"}, {"url": "https://i.ytimg.com/vi_webp/XnfMBo4IQ-g/maxresdefault.webp", "preference": 0, "id": "41"}], "thumbnail": "https://i.ytimg.com/vi/XnfMBo4IQ-g/sddefault.jpg", "description": "All rights reserved to the original owners. This video is for entertainment purposes only", "channel_id": "UCaeCsSA5_wkjCKr4Rz8t9rQ", "channel_url": "https://www.youtube.com/channel/UCaeCsSA5_wkjCKr4Rz8t9rQ", "duration": 245, "view_count": 38361, "average_rating": null, "age_limit": 0, "webpage_url": "https://www.youtube.com/watch?v=XnfMBo4IQ-g", "categories": ["Entertainment"], "tags": [], "playable_in_embed": true, "live_status": "not_live", "media_type": "video", "release_timestamp": null, "_format_sort_fields": ["quality", "res", "fps", "hdr:12", "source", "vcodec", "channels", "acodec", "lang", "proto"], "automatic_captions": {}, "subtitles": {}, "comment_count": 18, "chapters": null, "heatmap": null, "like_count": 421, "channel": "Heikki Rokkonen", "channel_follower_count": 356, "creators": null, "uploader": "Heikki Rokkonen", "uploader_id": "@hezerock1", "uploader_url": "https://www.youtube.com/@hezerock1", "upload_date": "20170812", "timestamp": 1502539541, "availability": "public", "original_url": "https://www.youtube.com/watch?v=XnfMBo4IQ-g", "webpage_url_basename": "watch", "webpage_url_domain": "youtube.com", "extractor": "youtube", "extractor_key": "Youtube", "playlist": null, "playlist_index": null, "display_id": "XnfMBo4IQ-g", "fulltitle": "Sentenced Noose", "duration_string": "4:05", "release_year": null, "is_live": false, "was_live": false, "requested_subtitles": null, "_has_drm": null, "epoch": 1785523497, "requested_downloads": [{"requested_formats": [{"asr": null, "filesize": 1562387, "format_id": "135", "format_note": "480p", "source_preference": -1, "fps": 30, "audio_channels": null, "height": 480, "quality": 7.0, "has_drm": false, "tbr": 51.014, "filesize_approx": 1562373, "width": 854, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.4d401f", "acodec": "none", "dynamic_range": "SDR", "container": "mp4_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=135&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=1562387&dur=245.011&lmt=1634500664956409&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgSrYBPX9JmxAE1w8sfoj9S3Nl0qRZ1S06oRfbd1Gl6vgCIQCiKhA9G8AwbeRDtR4O_KYNRFqlJZ98ym8ae6RgFeURVA%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "abr": 0, "vbr": 51.014, "resolution": "854x480", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "135 - 854x480 (480p)"}, {"asr": 48000, "filesize": 3804783, "format_id": "251", "format_note": "medium", "source_preference": -1, "fps": null, "audio_channels": 2, "height": null, "quality": 3.0, "has_drm": false, "tbr": 124.227, "filesize_approx": 3804777, "width": null, "language": null, "language_preference": -1, "preference": null, "ext": "webm", "vcodec": "none", "acodec": "opus", "dynamic_range": null, "container": "webm_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=251&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=audio%2Fwebm&rqh=1&gir=yes&clen=3804783&dur=245.021&lmt=1744051873395760&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=8208224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgMpOgu2rpc7C8EK2vhVaj5JHJ05A9E_HB-XYQ5GpGPBgCIQCIGSKoZ4uTYxU6NiSmxbc8YhqN_dMvNV0-IjJca-Qipg%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "audio_ext": "webm", "video_ext": "none", "vbr": 0, "abr": 124.227, "resolution": "audio only", "aspect_ratio": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "251 - audio only (medium)"}], "format": "135 - 854x480 (480p)+251 - audio only (medium)", "format_id": "135+251", "ext": "mkv", "protocol": "https+https", "format_note": "480p+medium", "filesize_approx": 5367170, "tbr": 175.241, "width": 854, "height": 480, "resolution": "854x480", "fps": 30, "dynamic_range": "SDR", "vcodec": "avc1.4d401f", "vbr": 51.014, "aspect_ratio": 1.78, "acodec": "opus", "abr": 124.227, "asr": 48000, "audio_channels": 2, "_filename": "Sentenced Noose [XnfMBo4IQ-g].mkv", "filename": "Sentenced Noose [XnfMBo4IQ-g].mkv", "__write_download_archive": false}], "requested_formats": [{"asr": null, "filesize": 1562387, "format_id": "135", "format_note": "480p", "source_preference": -1, "fps": 30, "audio_channels": null, "height": 480, "quality": 7.0, "has_drm": false, "tbr": 51.014, "filesize_approx": 1562373, "width": 854, "language": null, "language_preference": -1, "preference": null, "ext": "mp4", "vcodec": "avc1.4d401f", "acodec": "none", "dynamic_range": "SDR", "container": "mp4_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=135&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=1562387&dur=245.011&lmt=1634500664956409&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=5311222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgSrYBPX9JmxAE1w8sfoj9S3Nl0qRZ1S06oRfbd1Gl6vgCIQCiKhA9G8AwbeRDtR4O_KYNRFqlJZ98ym8ae6RgFeURVA%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "video_ext": "mp4", "audio_ext": "none", "abr": 0, "vbr": 51.014, "resolution": "854x480", "aspect_ratio": 1.78, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "135 - 854x480 (480p)"}, {"asr": 48000, "filesize": 3804783, "format_id": "251", "format_note": "medium", "source_preference": -1, "fps": null, "audio_channels": 2, "height": null, "quality": 3.0, "has_drm": false, "tbr": 124.227, "filesize_approx": 3804777, "width": null, "language": null, "language_preference": -1, "preference": null, "ext": "webm", "vcodec": "none", "acodec": "opus", "dynamic_range": null, "container": "webm_dash", "url": "https://rr1---sn-ajixh5-55.googlevideo.com/videoplayback?expire=1785545097&ei=Ke1sarK1EauMv_IPneKNuAc&ip=109.204.176.152&id=o-ABUhklpwF0YX76urGRkSgwb9W6VUJAU6i_FspGBsaQpX&itag=251&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=361&met=1785523497%2C&mh=7d&mm=31%2C29&mn=sn-ajixh5-55%2Csn-ixh7rn76&ms=au%2Crdu&mv=m&mvi=1&pl=22&rms=au%2Cau&initcwndbps=3910000&bui=AZFlqhNRLwpfPdFYhtIDUKbcoqQcAan5J3QojmFrbgGut5kBSw17qL0F2TUQ6hbpjgxdjisKnTlITm9e&spc=KBGBcjYipUFxIJps4rKYmwgs7y_IHhmNEk7gMf0qnvzY&vprv=1&svpuc=1&mime=audio%2Fwebm&rqh=1&gir=yes&clen=3804783&dur=245.021&lmt=1744051873395760&mt=1785522571&fvip=1&keepalive=yes&fexp=51565116&c=ANDROID_VR&txp=8208224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cbui%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AE0s2JYwRQIgMpOgu2rpc7C8EK2vhVaj5JHJ05A9E_HB-XYQ5GpGPBgCIQCIGSKoZ4uTYxU6NiSmxbc8YhqN_dMvNV0-IjJca-Qipg%3D%3D&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRAIgZ6z-VPIbsUpvGVtnJeR-8Q7I-Q8vk02VIR3ER_NVJtYCIB7VQPHW6yQKfzdNuBKzTtGynM7vBReAwpBYl8BgNYUR", "available_at": 1785523497, "downloader_options": {"http_chunk_size": 10485760}, "protocol": "https", "audio_ext": "webm", "video_ext": "none", "vbr": 0, "abr": 124.227, "resolution": "audio only", "aspect_ratio": null, "http_headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate"}, "format": "251 - audio only (medium)"}], "format": "135 - 854x480 (480p)+251 - audio only (medium)", "format_id": "135+251", "ext": "mkv", "protocol": "https+https", "language": null, "format_note": "480p+medium", "filesize_approx": 5367170, "tbr": 175.241, "width": 854, "height": 480, "resolution": "854x480", "fps": 30, "dynamic_range": "SDR", "vcodec": "avc1.4d401f", "vbr": 51.014, "stretched_ratio": null, "aspect_ratio": 1.78, "acodec": "opus", "abr": 124.227, "asr": 48000, "audio_channels": 2, "_type": "video", "_version": {"version": "2026.07.04", "current_git_head": null, "release_git_head": "997fa140840a08df3938b40da470c78049fef1f6", "repository": "yt-dlp/yt-dlp"}}