From 50f26333cb4477e55b1e4cff74ebcfe61a26c7b9 Mon Sep 17 00:00:00 2001 From: sybenx Date: Fri, 27 May 2022 23:17:38 -0600 Subject: [PATCH 01/92] remove 40two.app - dead/serves ads (#517) 40two.app looks like it serves ads instead of libreddit. Hasn't worked for 1 week+ --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 48dea6b..f78cdd1 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.spike.codes](https://libreddit.spike.codes) (official) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.dothq.co](https://libreddit.dothq.co) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | -| [libreddit.40two.app](https://libreddit.40two.app) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | | [reddit.invak.id](https://reddit.invak.id) | ๐Ÿ‡ง๐Ÿ‡ฌ BG | | | [reddit.phii.me](https://reddit.phii.me) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [lr.riverside.rocks](https://lr.riverside.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | From fd7d977835da0b4a3ca1f002509e0b381a5ee9cd Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Sat, 28 May 2022 05:31:07 +0000 Subject: [PATCH 02/92] Add instance rd.jae.su (close #515) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f78cdd1..cb10e47 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [reddit.beparanoid.de](https://reddit.beparanoid.de) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [libreddit.dcs0.hu](https://libreddit.dcs0.hu) | ๐Ÿ‡ญ๐Ÿ‡บ HU | | | [reddit.dr460nf1r3.org](https://reddit.dr460nf1r3.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | +| [rd.jae.su](https://rd.jae.su) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | @@ -105,6 +106,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion](http://lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion](http://libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion](http://reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | +| [inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion](http://inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare.com). The checkmark will not be listed for a site that uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website. From a8a8980b9896c6edd9b0ae42205e21218fe78ae6 Mon Sep 17 00:00:00 2001 From: guaddy <67671414+guaddy@users.noreply.github.com> Date: Fri, 27 May 2022 22:31:38 -0700 Subject: [PATCH 03/92] Update README.md (#516) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cb10e47..ccccad4 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.alefvanoon.xyz](https://libreddit.alefvanoon.xyz) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [libreddit.igna.rocks](https://libreddit.igna.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.autarkic.org](https://libreddit.autarkic.org) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.flux.industries](https://libreddit.flux.industries) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | From 5f20e8ee2700180fa99ce22feb9202373fe0710c Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Sat, 28 May 2022 19:55:13 -0700 Subject: [PATCH 04/92] Fix dark theme hidden in settings --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 4 ++-- static/themes/dark.css | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 static/themes/dark.css diff --git a/Cargo.lock b/Cargo.lock index f138b37..2c5da4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,9 +484,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown 0.11.2", @@ -586,7 +586,7 @@ checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libreddit" -version = "0.22.8" +version = "0.22.9" dependencies = [ "askama", "async-recursion", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -721,9 +721,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" [[package]] name = "parking" diff --git a/Cargo.toml b/Cargo.toml index 5c856cf..484962c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.22.8" +version = "0.22.9" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" @@ -16,7 +16,7 @@ regex = "1.5.6" serde = { version = "1.0.137", features = ["derive"] } cookie = "0.16.0" futures-lite = "1.12.0" -hyper = { version = "0.14.18", features = ["full"] } +hyper = { version = "0.14.19", features = ["full"] } hyper-rustls = "0.23.0" percent-encoding = "2.1.0" route-recognizer = "0.3.1" diff --git a/static/themes/dark.css b/static/themes/dark.css new file mode 100644 index 0000000..ef7b32c --- /dev/null +++ b/static/themes/dark.css @@ -0,0 +1,14 @@ +/* Dark theme setting */ +.dark{ + --accent: aqua; + --green: #5cff85; + --text: white; + --foreground: #222; + --background: #0f0f0f; + --outside: #1f1f1f; + --post: #161616; + --panel-border: 1px solid #333; + --highlighted: #333; + --visited: #aaa; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} \ No newline at end of file From 23569206cc1efa175905c28267e93156bc5c2472 Mon Sep 17 00:00:00 2001 From: Artemis <51862164+artemislena@users.noreply.github.com> Date: Mon, 6 Jun 2022 04:09:36 +0200 Subject: [PATCH 05/92] L: Fixed two swapped config variables in the documentation. (#524) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ccccad4..df08a8d 100644 --- a/README.md +++ b/README.md @@ -266,8 +266,8 @@ Assign a default value for each setting by passing environment variables to Libr | `FRONT_PAGE` | `["default", "popular", "all"]` | `default` | | `LAYOUT` | `["card", "clean", "compact"]` | `card` | | `WIDE` | `["on", "off"]` | `off` | -| `COMMENT_SORT` | `["hot", "new", "top", "rising", "controversial"]` | `hot` | -| `POST_SORT` | `["confidence", "top", "new", "controversial", "old"]` | `confidence` | +| `POST_SORT` | `["hot", "new", "top", "rising", "controversial"]` | `hot` | +| `COMMENT_SORT` | `["confidence", "top", "new", "controversial", "old"]` | `confidence` | | `SHOW_NSFW` | `["on", "off"]` | `off` | | `USE_HLS` | `["on", "off"]` | `off` | | `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` | From 93f089c2cf4456dc0e9f272a99aefd3dd412b2ff Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Sat, 11 Jun 2022 20:39:11 +0000 Subject: [PATCH 06/92] Add libreddit.foss.wtf (Close #527) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df08a8d..ccddc4d 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.dcs0.hu](https://libreddit.dcs0.hu) | ๐Ÿ‡ญ๐Ÿ‡บ HU | | | [reddit.dr460nf1r3.org](https://reddit.dr460nf1r3.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [rd.jae.su](https://rd.jae.su) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | +| [libreddit.foss.wtf](https://libreddit.foss.wtf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | From ff4a515e24d8030e9952a3ef31a48e0b0e9e9acc Mon Sep 17 00:00:00 2001 From: Arya K <73596856+gi-yt@users.noreply.github.com> Date: Sun, 12 Jun 2022 02:09:29 +0530 Subject: [PATCH 07/92] change lr.vern.cc hosting location as we moved vps (#526) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ccddc4d..d62b1da 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.hu](https://libreddit.hu) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | โœ… | | [libreddit.totaldarkness.net](https://libreddit.totaldarkness.net) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.esmailelbob.xyz](https://libreddit.esmailelbob.xyz) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [lr.vern.cc](https://lr.vern.cc) | ๐Ÿ‡ต๐Ÿ‡ฑ PL | | +| [lr.vern.cc](https://lr.vern.cc) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.nl](https://libreddit.nl) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | | [lr.stilic.ml](https://lr.stilic.ml) | ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | | [reddi.tk](https://reddi.tk) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | From 2bc714d0c53e34f20236284a349842290d6d9a7f Mon Sep 17 00:00:00 2001 From: Edward <101938856+EdwardLangdon@users.noreply.github.com> Date: Sat, 11 Jun 2022 20:41:54 +0000 Subject: [PATCH 08/92] Added mha.fi Instance (#519) Close #518 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d62b1da..08b624d 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.dcs0.hu](https://libreddit.dcs0.hu) | ๐Ÿ‡ญ๐Ÿ‡บ HU | | | [reddit.dr460nf1r3.org](https://reddit.dr460nf1r3.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [rd.jae.su](https://rd.jae.su) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | +| [libreddit.mha.fi](https://libreddit.mha.fi) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.foss.wtf](https://libreddit.foss.wtf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | @@ -107,6 +108,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion](http://libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion](http://reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion](http://inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | +| [libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion](http://libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion/)| ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare.com). The checkmark will not be listed for a site that uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website. From 36c560144a056a2fc624b38bddf20a530c69ea7a Mon Sep 17 00:00:00 2001 From: Dyras Date: Fri, 24 Jun 2022 19:48:41 +0200 Subject: [PATCH 09/92] Remove libreddit.awesomehub.io (#535) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 08b624d..f4f9d74 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.jamiethalacker.dev](https://libreddit.jamiethalacker.dev) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [reddit.artemislena.eu](https://reddit.artemislena.eu) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [r.nf](https://r.nf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [libreddit.awesomehub.io](https://libreddit.awesomehub.io) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | From b5f21bcb97d4481480d4b30f94c192d7859bffbd Mon Sep 17 00:00:00 2001 From: Edward <101938856+EdwardLangdon@users.noreply.github.com> Date: Fri, 24 Jun 2022 17:50:16 +0000 Subject: [PATCH 10/92] Added 3 instances (#531) * Add Instance - encrypted-data.xyz * Add Instance - eu.org * Add Instance - opnxng.com --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f4f9d74..f36823c 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,9 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [rd.jae.su](https://rd.jae.su) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.mha.fi](https://libreddit.mha.fi) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.foss.wtf](https://libreddit.foss.wtf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | +| [libreddit.encrypted-data.xyz](https://libreddit.encrypted-data.xyz)| ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | +| [libreddit.eu.org](https://libreddit.eu.org)| ๐Ÿ‡ฎ๐Ÿ‡ช IE | โœ… | +| [l.opnxng.com](https://l.opnxng.com)| ๐Ÿ‡ธ๐Ÿ‡ฌ SG | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | From 57d304161b3af6bee4ff849f39d80e7a6d020510 Mon Sep 17 00:00:00 2001 From: Arya K <73596856+gi-yt@users.noreply.github.com> Date: Fri, 24 Jun 2022 23:22:08 +0530 Subject: [PATCH 11/92] Add ~vern onion instance (#537) * Add ~vern onion instance Add vern.cc's onion instance of libreddit to instance list * Remove http:// from link name * Fix previous commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f36823c..5a941f3 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion](http://reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion](http://inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion](http://libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion/)| ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | - +| [lr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion](http://lr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare.com). The checkmark will not be listed for a site that uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website. --- From 8141b7481761b91d51fa5d85e233ab70f60eb787 Mon Sep 17 00:00:00 2001 From: Esmail EL BoB Date: Tue, 1 Nov 2022 00:45:05 +0000 Subject: [PATCH 12/92] Update Esmail's onion instance (#593) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a941f3..702d03a 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion](http://libreddit.2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion) | ๐Ÿ‡ช๐Ÿ‡ฌ EG | | | [ol5begilptoou34emq2sshf3may3hlblvipdjtybbovpb7c7zodxmtqd.onion](http://ol5begilptoou34emq2sshf3may3hlblvipdjtybbovpb7c7zodxmtqd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion](http://lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion](http://libreddit.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | +| [libreddit.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion](http://libreddit.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion](http://reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion](http://inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | | [libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion](http://libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion/)| ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | From ef86c1be86140fb7a7dbbc16684e69486833101d Mon Sep 17 00:00:00 2001 From: Artemis <51862164+artemislena@users.noreply.github.com> Date: Tue, 1 Nov 2022 01:46:16 +0100 Subject: [PATCH 13/92] Remove reddit.artemislena.eu (uses Teddit, not Libreddit now) (#586) * L: Fixed two swapped config variables in the documentation. * L: reddit.artemislena.eu is now Teddit, not Libreddit anymore --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 702d03a..3772b9a 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.domain.glass](https://libreddit.domain.glass) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [libreddit.sugoma.tk](https://libreddit.sugoma.tk) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.jamiethalacker.dev](https://libreddit.jamiethalacker.dev) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | -| [reddit.artemislena.eu](https://reddit.artemislena.eu) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [r.nf](https://r.nf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | From 0704eb10b80a3f758426d7ca2b42eecdcd3e517d Mon Sep 17 00:00:00 2001 From: Om G <34579088+OxyMagnesium@users.noreply.github.com> Date: Mon, 31 Oct 2022 20:49:20 -0400 Subject: [PATCH 14/92] Add new instance (libreddit.oxymagnesium.com) (#591) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3772b9a..359b649 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.encrypted-data.xyz](https://libreddit.encrypted-data.xyz)| ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | | [libreddit.eu.org](https://libreddit.eu.org)| ๐Ÿ‡ฎ๐Ÿ‡ช IE | โœ… | | [l.opnxng.com](https://l.opnxng.com)| ๐Ÿ‡ธ๐Ÿ‡ฌ SG | | +| [libreddit.oxymagnesium.com](https://libreddit.oxymagnesium.com) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | From 711e3c205d46cf1bf8d2ac71835903180299a12d Mon Sep 17 00:00:00 2001 From: Vladislav Nepogodin Date: Tue, 1 Nov 2022 00:50:59 +0000 Subject: [PATCH 15/92] Add libreddit.cachyos.org instance (#571) Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 359b649..7be5ede 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.encrypted-data.xyz](https://libreddit.encrypted-data.xyz)| ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | | [libreddit.eu.org](https://libreddit.eu.org)| ๐Ÿ‡ฎ๐Ÿ‡ช IE | โœ… | | [l.opnxng.com](https://l.opnxng.com)| ๐Ÿ‡ธ๐Ÿ‡ฌ SG | | +| [libreddit.cachyos.org](https://libreddit.cachyos.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.oxymagnesium.com](https://libreddit.oxymagnesium.com) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | From 8d58cf61d28d5ef8cea64e14229994367d954635 Mon Sep 17 00:00:00 2001 From: guaddy <67671414+guaddy@users.noreply.github.com> Date: Mon, 31 Oct 2022 18:06:32 -0700 Subject: [PATCH 16/92] Removed 8 dead links from instance list (#545) * Update README.md Removed the following instances for dead links: * libreddit.sugoma.tk * libreddit.jamiethalacker.dev * libreddit.database.red * reddit.phii.me * libreddit.autarkic.org * lr.oversold.host * libreddit.datatunnel.xyz * libreddit.crewz.me * Fix double pipe on flux.industries instance Co-authored-by: Mohammed Anas Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> Co-authored-by: Mohammed Anas --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index 7be5ede..c975269 100644 --- a/README.md +++ b/README.md @@ -40,23 +40,17 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.dothq.co](https://libreddit.dothq.co) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [reddit.invak.id](https://reddit.invak.id) | ๐Ÿ‡ง๐Ÿ‡ฌ BG | | -| [reddit.phii.me](https://reddit.phii.me) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [lr.riverside.rocks](https://lr.riverside.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.strongthany.cc](https://libreddit.strongthany.cc) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.database.red](https://libreddit.database.red) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [libreddit.privacy.com.de](https://libreddit.privacy.com.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.domain.glass](https://libreddit.domain.glass) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | -| [libreddit.sugoma.tk](https://libreddit.sugoma.tk) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.jamiethalacker.dev](https://libreddit.jamiethalacker.dev) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [r.nf](https://r.nf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.igna.rocks](https://libreddit.igna.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.autarkic.org](https://libreddit.autarkic.org) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.flux.industries](https://libreddit.flux.industries) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.drivet.xyz](https://libreddit.drivet.xyz) | ๐Ÿ‡ต๐Ÿ‡ฑ PL | | -| [lr.oversold.host](https://lr.oversold.host) | ๐Ÿ‡ฑ๐Ÿ‡บ LU | | +| [libreddit.flux.industries](https://libreddit.flux.industries) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.de](https://libreddit.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.pussthecat.org](https://libreddit.pussthecat.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.mutahar.rocks](https://libreddit.mutahar.rocks) | ๐Ÿ‡ซ๐Ÿ‡ท FR | | @@ -72,8 +66,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [lr.stilic.ml](https://lr.stilic.ml) | ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | | [reddi.tk](https://reddi.tk) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [libreddit.bus-hit.me](https://libreddit.bus-hit.me) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.datatunnel.xyz](https://libreddit.datatunnel.xyz) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | -| [libreddit.crewz.me](https://libreddit.crewz.me) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | โœ… | | [r.walkx.org](https://r.walkx.org) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | โœ… | | [libreddit.kylrth.com](https://libreddit.kylrth.com) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.yonalee.eu](https://libreddit.yonalee.eu) | ๐Ÿ‡ฑ๐Ÿ‡บ LU | โœ… | From 4fc07c02b55da6cdcd52a27eec2d73d68e9472fd Mon Sep 17 00:00:00 2001 From: igna Date: Mon, 31 Oct 2022 22:22:20 -0300 Subject: [PATCH 17/92] update instance (igna.rocks => intent.cool) (#603) * update instance (igna.rocks => intent.cool) * Remove accidentally-added broken instances Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c975269..ce57dcc 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,8 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.igna.rocks](https://libreddit.igna.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | +| [libreddit.intent.cool](https://libreddit.intent.cool) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [libreddit.drivet.xyz](https://libreddit.drivet.xyz) | ๐Ÿ‡ต๐Ÿ‡ฑ PL | | -| [libreddit.flux.industries](https://libreddit.flux.industries) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | | [libreddit.de](https://libreddit.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.pussthecat.org](https://libreddit.pussthecat.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.mutahar.rocks](https://libreddit.mutahar.rocks) | ๐Ÿ‡ซ๐Ÿ‡ท FR | | From 1a1ff2e60093bd14d194fc57132346be8259ee7f Mon Sep 17 00:00:00 2001 From: arthomnix <35371030+arthomnix@users.noreply.github.com> Date: Tue, 1 Nov 2022 01:36:24 +0000 Subject: [PATCH 18/92] Use singular form of "comment" for posts with 1 comment (#567) * Use singular form of "comment" for posts with 1 comment * Fix incorrect text on comment count tooltip Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- templates/utils.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/utils.html b/templates/utils.html index 07e1ce8..7864200 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -141,7 +141,7 @@ {{ post.body|safe }} {%- endmacro %} From b4d3f03335cc32e48cd1fec362acde56669ea203 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Mon, 31 Oct 2022 20:23:59 -0700 Subject: [PATCH 19/92] Upgrade dependencies --- Cargo.lock | 531 ++++++++++++++++++++++++++++------------------------ Cargo.toml | 24 +-- src/main.rs | 14 +- 3 files changed, 302 insertions(+), 267 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c5da4d..e263b06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.53" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -90,9 +90,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "bitflags" @@ -102,37 +102,47 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] [[package]] -name = "bumpalo" -version = "3.9.1" +name = "bstr" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cached" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aadf76ddea74bab35ebeb8f1eb115b9bc04eaee42d8acc0d5f477dee6b176c9a" +checksum = "72b4147cd94d5fbdc2ab71b11d50a2f45493625576b3bb70257f59eedea69f3d" dependencies = [ "async-trait", "async_once", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown 0.12.1", + "hashbrown", + "instant", "lazy_static", "once_cell", "thiserror", @@ -141,9 +151,9 @@ dependencies = [ [[package]] name = "cached_proc_macro" -version = "0.12.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce0f37f9b77c6b93cdf3f060c89adca303d2ab052cacb3c3d1ab543e8cecd2f" +checksum = "751f7f4e7a091545e7f6c65bacc404eaee7e87bfb1f9ece234a1caa173dc16f2" dependencies = [ "cached_proc_macro_types", "darling", @@ -159,9 +169,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" [[package]] name = "cfg-if" @@ -171,30 +181,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.18" +version = "4.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" dependencies = [ "bitflags", "clap_lex", - "indexmap", - "textwrap", ] [[package]] name = "clap_lex" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] [[package]] name = "cookie" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" dependencies = [ "time", "version_check", @@ -218,13 +226,23 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "darling" version = "0.13.4" @@ -262,18 +280,19 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "generic-array", + "block-buffer", + "crypto-common", ] [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -286,23 +305,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] [[package]] name = "futures" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -311,9 +328,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -321,26 +338,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" - -[[package]] -name = "futures-executor" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-lite" @@ -357,62 +363,59 @@ dependencies = [ "waker-fn", ] -[[package]] -name = "futures-macro" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", ] [[package]] -name = "h2" -version = "0.3.13" +name = "globset" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -429,15 +432,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hermit-abi" @@ -450,9 +447,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", @@ -472,9 +469,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -484,9 +481,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.19" +version = "0.14.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" dependencies = [ "bytes", "futures-channel", @@ -529,23 +526,22 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -559,15 +555,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -580,9 +576,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libreddit" @@ -609,9 +605,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -626,12 +622,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" version = "2.5.0" @@ -662,14 +652,14 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -703,15 +693,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "openssl-probe" @@ -721,9 +705,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.1.0" +version = "6.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" [[package]] name = "parking" @@ -733,9 +717,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", @@ -743,22 +727,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project-lite" @@ -774,36 +758,36 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -812,9 +796,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "ring" @@ -839,9 +823,9 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rust-embed" -version = "6.4.0" +version = "6.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +checksum = "283ffe2f866869428c92e0d61c2f35dfb4355293cdfdc48f49e895c15f1333d1" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -850,9 +834,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "6.2.0" +version = "6.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +checksum = "31ab23d42d71fb9be1b643fe6765d292c5e14d46912d13f3ae2815ca048ea04d" dependencies = [ "proc-macro2", "quote", @@ -863,19 +847,20 @@ dependencies = [ [[package]] name = "rust-embed-utils" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +checksum = "c1669d81dfabd1b5f8e2856b8bbe146c6192b0ba22162edc738ac0a5de18f054" dependencies = [ + "globset", "sha2", "walkdir", ] [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", @@ -897,18 +882,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ "base64", ] [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "same-file" @@ -926,7 +911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -947,9 +932,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -970,18 +955,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -990,9 +975,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ "itoa", "ryu", @@ -1001,15 +986,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.9" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] @@ -1023,21 +1006,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -1057,35 +1043,29 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -1094,21 +1074,32 @@ dependencies = [ [[package]] name = "time" -version = "0.3.9" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" dependencies = [ "itoa", "libc", "num_threads", + "serde", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +dependencies = [ + "time-core", +] [[package]] name = "tinyvec" @@ -1127,16 +1118,16 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.18.2" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", - "once_cell", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -1147,9 +1138,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -1169,9 +1160,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -1183,40 +1174,28 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.34" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -1248,15 +1227,15 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] @@ -1269,13 +1248,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] @@ -1320,9 +1298,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1330,13 +1308,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -1345,9 +1323,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1355,9 +1333,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -1368,15 +1346,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1429,39 +1407,96 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/Cargo.toml b/Cargo.toml index 484962c..0fe033c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,18 +10,18 @@ edition = "2021" [dependencies] askama = { version = "0.11.1", default-features = false } async-recursion = "1.0.0" -cached = "0.34.0" -clap = { version = "3.1.18", default-features = false, features = ["std"] } -regex = "1.5.6" -serde = { version = "1.0.137", features = ["derive"] } -cookie = "0.16.0" +cached = "0.40.0" +clap = { version = "4.0.18", default-features = false, features = ["std"] } +regex = "1.6.0" +serde = { version = "1.0.147", features = ["derive"] } +cookie = "0.16.1" futures-lite = "1.12.0" -hyper = { version = "0.14.19", features = ["full"] } +hyper = { version = "0.14.22", features = ["full"] } hyper-rustls = "0.23.0" -percent-encoding = "2.1.0" +percent-encoding = "2.2.0" route-recognizer = "0.3.1" -serde_json = "1.0.81" -tokio = { version = "1.18.2", features = ["full"] } -time = "0.3.9" -url = "2.2.2" -rust-embed = "6.4.0" +serde_json = "1.0.87" +tokio = { version = "1.21.2", features = ["full"] } +time = "0.3.16" +url = "2.3.1" +rust-embed = { version = "6.4.2", features = ["include-exclude"] } diff --git a/src/main.rs b/src/main.rs index b6f7889..37871b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -112,7 +112,7 @@ async fn main() { .short('r') .long("redirect-https") .help("Redirect all HTTP requests to HTTPS (no longer functional)") - .takes_value(false), + .num_args(0), ) .arg( Arg::new("address") @@ -121,7 +121,7 @@ async fn main() { .value_name("ADDRESS") .help("Sets address to listen on") .default_value("0.0.0.0") - .takes_value(true), + .num_args(1), ) .arg( Arg::new("port") @@ -130,7 +130,7 @@ async fn main() { .value_name("PORT") .help("Port to listen on") .default_value("8080") - .takes_value(true), + .num_args(1), ) .arg( Arg::new("hsts") @@ -139,13 +139,13 @@ async fn main() { .value_name("EXPIRE_TIME") .help("HSTS header to tell browsers that this site should only be accessed over HTTPS") .default_value("604800") - .takes_value(true), + .num_args(1), ) .get_matches(); - let address = matches.value_of("address").unwrap_or("0.0.0.0"); - let port = std::env::var("PORT").unwrap_or_else(|_| matches.value_of("port").unwrap_or("8080").to_string()); - let hsts = matches.value_of("hsts"); + let address = matches.get_one("address").map(|m: &String| m.as_str()).unwrap_or("0.0.0.0"); + let port = std::env::var("PORT").unwrap_or_else(|_| matches.get_one("port").map(|m: &String| m.as_str()).unwrap_or("8080").to_string()); + let hsts = matches.get_one("hsts").map(|m: &String| m.as_str()); let listener = [address, ":", &port].concat(); From aa5430105482e36c6a0dc1cb82f17ac0c0365997 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Mon, 31 Oct 2022 20:35:00 -0700 Subject: [PATCH 20/92] Upgrade to version 0.23 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e263b06..c10f9c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,7 +582,7 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libreddit" -version = "0.22.9" +version = "0.23.0" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 0fe033c..c272f3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.22.9" +version = "0.23.0" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From b170a8dd99dabea17d34a5bdfd717da33725492e Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Mon, 31 Oct 2022 22:30:31 -0700 Subject: [PATCH 21/92] Switch Reveddit to Unddit --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/post.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c10f9c9..9937801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,7 +582,7 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libreddit" -version = "0.23.0" +version = "0.23.1" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index c272f3c..adf135a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.23.0" +version = "0.23.1" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" diff --git a/src/post.rs b/src/post.rs index 02ca380..5f3142a 100644 --- a/src/post.rs +++ b/src/post.rs @@ -100,7 +100,7 @@ async fn parse_post(json: &serde_json::Value) -> Post { let body = if val(post, "removed_by_category") == "moderator" { format!( - "

[removed] โ€” view removed post

", + "

[removed] โ€” view removed post

", permalink ) } else { @@ -200,9 +200,9 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, let id = val(&comment, "id"); let highlighted = id == highlighted_comment; - let body = if val(&comment, "author") == "[deleted]" && val(&comment, "body") == "[removed]" { + let body = if (val(&comment, "author") == "[deleted]" && val(&comment, "body") == "[removed]") || val(&comment, "body") == "[ Removed by Reddit ]" { format!( - "

[removed] โ€” view removed comment

", + "

[removed] โ€” view removed comment

", post_link, id ) } else { From 1b5e9a4279029cd444a3079a93b42843af0c9da2 Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Tue, 1 Nov 2022 20:47:47 -0700 Subject: [PATCH 22/92] Fix #592 --- .replit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.replit b/.replit index d365864..164ef4f 100644 --- a/.replit +++ b/.replit @@ -1,2 +1,2 @@ -run = "while true; do wget -O libreddit https://github.com/spikecodes/libreddit/releases/latest/download/libreddit;chmod +x libreddit;./libreddit -H 63115200;sleep 1;done" -language = "bash" \ No newline at end of file +run = "while :; do set -ex; curl -o./libreddit -fsSL -- https://github.com/libreddit/libreddit/releases/latest/download/libreddit ; chmod +x libreddit; set +e; ./libreddit -H 63115200; sleep 1; done" +language = "bash" From 170ea384fbb6490494ef85d7279da9ce44d560a4 Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Tue, 1 Nov 2022 20:53:42 -0700 Subject: [PATCH 23/92] Support /comments endpoint (closes #568) Code based on @Daniel-Valentine's [implementation](https://github.com/ferritreader/libreddit-fork/commit/e2c84879d658f28d80c318b3bcc24f12e14c807a) --- src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.rs b/src/main.rs index 37871b0..4ce4a96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -238,6 +238,11 @@ async fn main() { app.at("/r/:sub/comments/:id").get(|r| post::item(r).boxed()); app.at("/r/:sub/comments/:id/:title").get(|r| post::item(r).boxed()); app.at("/r/:sub/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed()); + app.at("/comments/:id").get(|r| post::item(r).boxed()); + app.at("/comments/:id/comments").get(|r| post::item(r).boxed()); + app.at("/comments/:id/comments/:comment_id").get(|r| post::item(r).boxed()); + app.at("/comments/:id/:title").get(|r| post::item(r).boxed()); + app.at("/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed()); app.at("/r/:sub/search").get(|r| search::find(r).boxed()); From 98674310bceefadfa4391461838f0bc3dfb4680a Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Tue, 1 Nov 2022 21:29:50 -0700 Subject: [PATCH 24/92] Remove some-things.org instance (closes #561) --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index ce57dcc..988e896 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [libreddit.privacy.com.de](https://libreddit.privacy.com.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [libreddit.domain.glass](https://libreddit.domain.glass) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | | [r.nf](https://r.nf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [libreddit.some-things.org](https://libreddit.some-things.org) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | | [libreddit.intent.cool](https://libreddit.intent.cool) | ๐Ÿ‡บ๐Ÿ‡ธ US | | @@ -90,7 +89,6 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) | [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | | [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | -| [inytumdgnri7xsqtvpntjevaelxtgbjqkuqhtf6txxhwbll2fwqtakqd.onion](http://inytumdgnri7xsqtvpntjevaelxtgbjqkuqhtf6txxhwbll2fwqtakqd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | | [liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion](http://liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | | [kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion](http://kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion) | ๐Ÿ‡บ๐Ÿ‡ธ US | | | [ecue64ybzvn6vjzl37kcsnwt4ycmbsyf74nbttyg7rkc3t3qwnj7mcyd.onion](http://ecue64ybzvn6vjzl37kcsnwt4ycmbsyf74nbttyg7rkc3t3qwnj7mcyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | From 510c8679d68af5590ede0e3209ed6032a73e84d2 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Tue, 1 Nov 2022 21:59:16 -0700 Subject: [PATCH 25/92] Show full "Submissions" btn on mobile (fixes #548) --- static/style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/style.css b/static/style.css index 3e0d64d..d8bebff 100644 --- a/static/style.css +++ b/static/style.css @@ -480,6 +480,10 @@ button.submit:hover > svg { stroke: var(--accent); } margin-bottom: 20px; } +#listing_options { + overflow-x: auto; +} + #sort_options, #listing_options, footer > a { border-radius: 5px; align-items: center; From 8435b8eab9cce8abefd1fa8c69c243ecc06b324c Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Wed, 2 Nov 2022 08:46:59 -0700 Subject: [PATCH 26/92] Update hls.js.min to v1.2.4 Mirrors ferritreader/ferrit#6 --- static/hls.min.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/hls.min.js b/static/hls.min.js index a02b51e..1f65b75 100644 --- a/static/hls.min.js +++ b/static/hls.min.js @@ -1,5 +1,5 @@ // @license http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0 -// @source https://github.com/video-dev/hls.js -"undefined"!=typeof window&&function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Hls=e():t.Hls=e()}(this,(function(){return function(t){var e={};function r(i){if(e[i])return e[i].exports;var a=e[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=t,r.c=e,r.d=function(t,e,i){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)r.d(i,a,function(e){return t[e]}.bind(null,a));return i},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="/dist/",r(r.s=19)}([function(t,e,r){"use strict";var i;r.d(e,"a",(function(){return i})),function(t){t.MEDIA_ATTACHING="hlsMediaAttaching",t.MEDIA_ATTACHED="hlsMediaAttached",t.MEDIA_DETACHING="hlsMediaDetaching",t.MEDIA_DETACHED="hlsMediaDetached",t.BUFFER_RESET="hlsBufferReset",t.BUFFER_CODECS="hlsBufferCodecs",t.BUFFER_CREATED="hlsBufferCreated",t.BUFFER_APPENDING="hlsBufferAppending",t.BUFFER_APPENDED="hlsBufferAppended",t.BUFFER_EOS="hlsBufferEos",t.BUFFER_FLUSHING="hlsBufferFlushing",t.BUFFER_FLUSHED="hlsBufferFlushed",t.MANIFEST_LOADING="hlsManifestLoading",t.MANIFEST_LOADED="hlsManifestLoaded",t.MANIFEST_PARSED="hlsManifestParsed",t.LEVEL_SWITCHING="hlsLevelSwitching",t.LEVEL_SWITCHED="hlsLevelSwitched",t.LEVEL_LOADING="hlsLevelLoading",t.LEVEL_LOADED="hlsLevelLoaded",t.LEVEL_UPDATED="hlsLevelUpdated",t.LEVEL_PTS_UPDATED="hlsLevelPtsUpdated",t.LEVELS_UPDATED="hlsLevelsUpdated",t.AUDIO_TRACKS_UPDATED="hlsAudioTracksUpdated",t.AUDIO_TRACK_SWITCHING="hlsAudioTrackSwitching",t.AUDIO_TRACK_SWITCHED="hlsAudioTrackSwitched",t.AUDIO_TRACK_LOADING="hlsAudioTrackLoading",t.AUDIO_TRACK_LOADED="hlsAudioTrackLoaded",t.SUBTITLE_TRACKS_UPDATED="hlsSubtitleTracksUpdated",t.SUBTITLE_TRACKS_CLEARED="hlsSubtitleTracksCleared",t.SUBTITLE_TRACK_SWITCH="hlsSubtitleTrackSwitch",t.SUBTITLE_TRACK_LOADING="hlsSubtitleTrackLoading",t.SUBTITLE_TRACK_LOADED="hlsSubtitleTrackLoaded",t.SUBTITLE_FRAG_PROCESSED="hlsSubtitleFragProcessed",t.CUES_PARSED="hlsCuesParsed",t.NON_NATIVE_TEXT_TRACKS_FOUND="hlsNonNativeTextTracksFound",t.INIT_PTS_FOUND="hlsInitPtsFound",t.FRAG_LOADING="hlsFragLoading",t.FRAG_LOAD_EMERGENCY_ABORTED="hlsFragLoadEmergencyAborted",t.FRAG_LOADED="hlsFragLoaded",t.FRAG_DECRYPTED="hlsFragDecrypted",t.FRAG_PARSING_INIT_SEGMENT="hlsFragParsingInitSegment",t.FRAG_PARSING_USERDATA="hlsFragParsingUserdata",t.FRAG_PARSING_METADATA="hlsFragParsingMetadata",t.FRAG_PARSED="hlsFragParsed",t.FRAG_BUFFERED="hlsFragBuffered",t.FRAG_CHANGED="hlsFragChanged",t.FPS_DROP="hlsFpsDrop",t.FPS_DROP_LEVEL_CAPPING="hlsFpsDropLevelCapping",t.ERROR="hlsError",t.DESTROYING="hlsDestroying",t.KEY_LOADING="hlsKeyLoading",t.KEY_LOADED="hlsKeyLoaded",t.LIVE_BACK_BUFFER_REACHED="hlsLiveBackBufferReached",t.BACK_BUFFER_REACHED="hlsBackBufferReached"}(i||(i={}))},function(t,e,r){"use strict";r.d(e,"a",(function(){return o})),r.d(e,"b",(function(){return l}));var i=function(){},a={trace:i,debug:i,log:i,warn:i,info:i,error:i},n=a;function s(t){var e=self.console[t];return e?e.bind(self.console,"["+t+"] >"):i}function o(t){if(self.console&&!0===t||"object"==typeof t){!function(t){for(var e=arguments.length,r=new Array(e>1?e-1:0),i=1;i>8*(15-r)&255;return e},r.setDecryptDataFromLevelKey=function(t,e){var r=t;return"AES-128"===(null==t?void 0:t.method)&&t.uri&&!t.iv&&((r=o.a.fromURI(t.uri)).method=t.method,r.iv=this.createInitializationVector(e),r.keyFormat="identity"),r},r.setElementaryStreamInfo=function(t,e,r,i,a,n){void 0===n&&(n=!1);var s=this.elementaryStreams,o=s[t];o?(o.startPTS=Math.min(o.startPTS,e),o.endPTS=Math.max(o.endPTS,r),o.startDTS=Math.min(o.startDTS,i),o.endDTS=Math.max(o.endDTS,a)):s[t]={startPTS:e,endPTS:r,startDTS:i,endDTS:a,partial:n}},r.clearElementaryStreamInfo=function(){var t=this.elementaryStreams;t[i.AUDIO]=null,t[i.VIDEO]=null,t[i.AUDIOVIDEO]=null},c(e,[{key:"decryptdata",get:function(){if(!this.levelkey&&!this._decryptdata)return null;if(!this._decryptdata&&this.levelkey){var t=this.sn;"number"!=typeof t&&(this.levelkey&&"AES-128"===this.levelkey.method&&!this.levelkey.iv&&s.b.warn('missing IV for initialization segment with method="'+this.levelkey.method+'" - compliance issue'),t=0),this._decryptdata=this.setDecryptDataFromLevelKey(this.levelkey,t)}return this._decryptdata}},{key:"end",get:function(){return this.start+this.duration}},{key:"endProgramDateTime",get:function(){if(null===this.programDateTime)return null;if(!Object(a.a)(this.programDateTime))return null;var t=Object(a.a)(this.duration)?this.duration:0;return this.programDateTime+1e3*t}},{key:"encrypted",get:function(){var t;return!(null===(t=this.decryptdata)||void 0===t||!t.keyFormat||!this.decryptdata.uri)}}]),e}(f),v=function(t){function e(e,r,i,a,n){var s;(s=t.call(this,i)||this).fragOffset=0,s.duration=0,s.gap=!1,s.independent=!1,s.relurl=void 0,s.fragment=void 0,s.index=void 0,s.stats=new l.a,s.duration=e.decimalFloatingPoint("DURATION"),s.gap=e.bool("GAP"),s.independent=e.bool("INDEPENDENT"),s.relurl=e.enumeratedString("URI"),s.fragment=r,s.index=a;var o=e.enumeratedString("BYTERANGE");return o&&s.setByteRange(o,n),n&&(s.fragOffset=n.fragOffset+n.duration),s}return u(e,t),c(e,[{key:"start",get:function(){return this.fragment.start+this.fragOffset}},{key:"end",get:function(){return this.start+this.duration}},{key:"loaded",get:function(){var t=this.elementaryStreams;return!!(t.audio||t.video||t.audiovideo)}}]),e}(f)},function(t,e,r){"use strict";r.d(e,"b",(function(){return h})),r.d(e,"g",(function(){return d})),r.d(e,"f",(function(){return c})),r.d(e,"d",(function(){return f})),r.d(e,"c",(function(){return g})),r.d(e,"e",(function(){return p})),r.d(e,"h",(function(){return m})),r.d(e,"a",(function(){return y}));var i=r(8),a=r(4),n=Math.pow(2,32)-1,s=[].push;function o(t){return String.fromCharCode.apply(null,t)}function l(t,e){"data"in t&&(e+=t.start,t=t.data);var r=t[e]<<24|t[e+1]<<16|t[e+2]<<8|t[e+3];return r<0?4294967296+r:r}function u(t,e,r){"data"in t&&(e+=t.start,t=t.data),t[e]=r>>24,t[e+1]=r>>16&255,t[e+2]=r>>8&255,t[e+3]=255&r}function h(t,e){var r,i,a,n=[];if(!e.length)return n;"data"in t?(r=t.data,i=t.start,a=t.end):(i=0,a=(r=t).byteLength);for(var u=i;u1?u+d:a;if(o(r.subarray(u+4,u+8))===e[0])if(1===e.length)n.push({data:r,start:u+8,end:c});else{var f=h({data:r,start:u+8,end:c},e.slice(1));f.length&&s.apply(n,f)}u=c}return n}function d(t){var e=h(t,["moov"])[0],r=e?e.end:null,i=h(t,["sidx"]);if(!i||!i[0])return null;var a=[],n=i[0],s=n.data[0],o=0===s?8:16,u=l(n,o);o+=4;o+=0===s?8:16,o+=2;var d=n.end+0,c=function(t,e){"data"in t&&(e+=t.start,t=t.data);var r=t[e]<<8|t[e+1];return r<0?65536+r:r}(n,o);o+=2;for(var f=0;f>>31)return console.warn("SIDX has hierarchical references (not supported)"),null;var m=l(n,g);g+=4,a.push({referenceSize:p,subsegmentDuration:m,info:{duration:m/u,start:d,end:d+p-1}}),d+=p,o=g+=4}return{earliestPresentationTime:0,timescale:u,version:s,referencesCount:c,references:a,moovEndOffset:r}}function c(t){for(var e=[],r=h(t,["moov","trak"]),i=0;i0)return t.subarray(r,r+i)},o=function(t,e){var r=0;return r=(127&t[e])<<21,r|=(127&t[e+1])<<14,r|=(127&t[e+2])<<7,r|=127&t[e+3]},l=function(t,e){return a(t,e)&&o(t,e+6)+10<=t.length-e},u=function(t){for(var e=c(t),r=0;r>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:u+=String.fromCharCode(n);break;case 12:case 13:s=t[h++],u+=String.fromCharCode((31&n)<<6|63&s);break;case 14:s=t[h++],o=t[h++],u+=String.fromCharCode((15&n)<<12|(63&s)<<6|(63&o)<<0)}}return u};function T(){return i||void 0===self.TextDecoder||(i=new self.TextDecoder("utf-8")),i}},function(t,e,r){"use strict";r.d(e,"c",(function(){return a})),r.d(e,"b",(function(){return n})),r.d(e,"a",(function(){return s}));function i(t,e,r,i){void 0===r&&(r=1),void 0===i&&(i=!1);var a=t*e*r;return i?Math.round(a):a}function a(t,e,r,a){return void 0===r&&(r=1),void 0===a&&(a=!1),i(t,e,1/r,a)}function n(t,e){return void 0===e&&(e=!1),i(t,1e3,1/9e4,e)}function s(t,e){return void 0===e&&(e=1),i(t,9e4,1/e)}},function(t,e,r){"use strict";function i(t,e,r){return Uint8Array.prototype.slice?t.slice(e,r):new Uint8Array(Array.prototype.slice.call(t,e,r))}r.d(e,"a",(function(){return i}))},function(t,e,r){"use strict";r.d(e,"c",(function(){return lt})),r.d(e,"d",(function(){return ht})),r.d(e,"a",(function(){return dt})),r.d(e,"b",(function(){return ct}));var i=r(0),a=r(2),n=r(14),s=r(3),o=r(6);var l=r(5),u=r(8),h=function(){function t(){this._audioTrack=void 0,this._id3Track=void 0,this.frameIndex=0,this.cachedData=null,this.initPTS=null}var e=t.prototype;return e.resetInitSegment=function(t,e,r){this._id3Track={type:"id3",id:0,pid:-1,inputTimeScale:9e4,sequenceNumber:0,samples:[],dropped:0}},e.resetTimeStamp=function(){},e.resetContiguity=function(){},e.canParse=function(t,e){return!1},e.appendFrame=function(t,e,r){},e.demux=function(t,e){this.cachedData&&(t=Object(l.a)(this.cachedData,t),this.cachedData=null);var r,i,a=o.b(t,0),n=a?a.length:0,s=this._audioTrack,h=this._id3Track,c=a?o.d(a):void 0,f=t.length;for(0!==this.frameIndex&&null!==this.initPTS||(this.initPTS=d(c,e)),a&&a.length>0&&h.samples.push({pts:this.initPTS,dts:this.initPTS,data:a}),i=this.initPTS;n>>5}function m(t,e){return e+1=t.length)return!1;var i=p(t,e);if(i<=r)return!1;var a=e+i;return a===t.length||m(t,a)}return!1}function T(t,e,r,n,s){if(!t.samplerate){var o=function(t,e,r,n){var s,o,l,u,h=navigator.userAgent.toLowerCase(),d=n,c=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350];s=1+((192&e[r+2])>>>6);var g=(60&e[r+2])>>>2;if(!(g>c.length-1))return l=(1&e[r+2])<<2,l|=(192&e[r+3])>>>6,f.b.log("manifest codec:"+n+", ADTS type:"+s+", samplingIndex:"+g),/firefox/i.test(h)?g>=6?(s=5,u=new Array(4),o=g-3):(s=2,u=new Array(2),o=g):-1!==h.indexOf("android")?(s=2,u=new Array(2),o=g):(s=5,u=new Array(4),n&&(-1!==n.indexOf("mp4a.40.29")||-1!==n.indexOf("mp4a.40.5"))||!n&&g>=6?o=g-3:((n&&-1!==n.indexOf("mp4a.40.2")&&(g>=6&&1===l||/vivaldi/i.test(h))||!n&&1===l)&&(s=2,u=new Array(2)),o=g)),u[0]=s<<3,u[0]|=(14&g)>>1,u[1]|=(1&g)<<7,u[1]|=l<<3,5===s&&(u[1]|=(14&o)>>1,u[2]=(1&o)<<7,u[2]|=8,u[3]=0),{config:u,samplerate:c[g],channelCount:l,codec:"mp4a.40."+s,manifestCodec:d};t.trigger(i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!0,reason:"invalid ADTS sampling index:"+g})}(e,r,n,s);if(!o)return;t.config=o.config,t.samplerate=o.samplerate,t.channelCount=o.channelCount,t.codec=o.codec,t.manifestCodec=o.manifestCodec,f.b.log("parsed codec:"+t.codec+", rate:"+o.samplerate+", channels:"+o.channelCount)}}function E(t){return 9216e4/t}function b(t,e,r,i,a){var n=function(t,e,r,i,a){var n=t.length,s=v(t,e),o=p(t,e);if((o-=s)>0&&e+s+o<=n)return{headerLength:s,frameLength:o,stamp:r+i*a}}(e,r,i,a,E(t.samplerate));if(n){var s=n.stamp,o=n.headerLength,l=n.frameLength,u={unit:e.subarray(r+o,r+o+l),pts:s,dts:s};return t.samples.push(u),{sample:u,length:l+o}}}function S(t,e){return(S=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}var L=function(t){var e,r;function i(e,r){var i;return(i=t.call(this)||this).observer=void 0,i.config=void 0,i.observer=e,i.config=r,i}r=t,(e=i).prototype=Object.create(r.prototype),e.prototype.constructor=e,S(e,r);var a=i.prototype;return a.resetInitSegment=function(e,r,i){t.prototype.resetInitSegment.call(this,e,r,i),this._audioTrack={container:"audio/adts",type:"audio",id:0,pid:-1,sequenceNumber:0,isAAC:!0,samples:[],manifestCodec:e,duration:i,inputTimeScale:9e4,dropped:0}},i.probe=function(t){if(!t)return!1;for(var e=(o.b(t,0)||[]).length,r=t.length;e0},e.demux=function(t){var e=t,r={type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0};if(this.config.progressive){this.remainderData&&(e=Object(l.a)(this.remainderData,t));var i=Object(l.h)(e);this.remainderData=i.remainder,r.samples=i.valid||new Uint8Array}else r.samples=e;return{audioTrack:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0},avcTrack:r,id3Track:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0},textTrack:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0}}},e.flush=function(){var t={type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0};return t.samples=this.remainderData||new Uint8Array,this.remainderData=null,{audioTrack:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0},avcTrack:t,id3Track:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0},textTrack:{type:"",id:-1,pid:-1,inputTimeScale:9e4,sequenceNumber:-1,samples:[],dropped:0}}},e.demuxSampleAes=function(t,e,r){return Promise.reject(new Error("The MP4 demuxer does not support SAMPLE-AES decryption"))},e.destroy=function(){},t}();R.minProbeByteLength=1024;var D=R,k=null,_=[32,64,96,128,160,192,224,256,288,320,352,384,416,448,32,48,56,64,80,96,112,128,160,192,224,256,320,384,32,40,48,56,64,80,96,112,128,160,192,224,256,320,32,48,56,64,80,96,112,128,144,160,176,192,224,256,8,16,24,32,40,48,56,64,80,96,112,128,144,160],I=[44100,48e3,32e3,22050,24e3,16e3,11025,12e3,8e3],C=[[0,72,144,12],[0,0,0,0],[0,72,144,12],[0,144,144,12]],w=[0,1,1,4];function O(t,e,r,i,a){if(!(r+24>e.length)){var n=x(e,r);if(n&&r+n.frameLength<=e.length){var s=i+a*(9e4*n.samplesPerFrame/n.sampleRate),o={unit:e.subarray(r,r+n.frameLength),pts:s,dts:s};return t.config=[],t.channelCount=n.channelCount,t.samplerate=n.sampleRate,t.samples.push(o),{sample:o,length:n.frameLength}}}}function x(t,e){var r=t[e+1]>>3&3,i=t[e+1]>>1&3,a=t[e+2]>>4&15,n=t[e+2]>>2&3;if(1!==r&&0!==a&&15!==a&&3!==n){var s=t[e+2]>>1&1,o=t[e+3]>>6,l=1e3*_[14*(3===r?3-i:3===i?3:4)+a-1],u=I[3*(3===r?0:2===r?1:2)+n],h=3===o?1:2,d=C[r][i],c=w[i],f=8*d*c,g=Math.floor(d*l/u+s)*c;if(null===k){var v=(navigator.userAgent||"").match(/Chrome\/(\d+)/i);k=v?parseInt(v[1]):0}return!!k&&k<=87&&2===i&&l>=224e3&&0===o&&(t[e+3]=128|t[e+3]),{sampleRate:u,channelCount:h,frameLength:g,samplesPerFrame:f}}}function P(t,e){return 255===t[e]&&224==(224&t[e+1])&&0!=(6&t[e+1])}function M(t,e){return e+1t?(this.word<<=t,this.bitsAvailable-=t):(t-=this.bitsAvailable,t-=(e=t>>3)>>3,this.bytesAvailable-=e,this.loadWord(),this.word<<=t,this.bitsAvailable-=t)},e.readBits=function(t){var e=Math.min(this.bitsAvailable,t),r=this.word>>>32-e;return t>32&&f.b.error("Cannot read more than 32 bits at a time"),this.bitsAvailable-=e,this.bitsAvailable>0?this.word<<=e:this.bytesAvailable>0&&this.loadWord(),(e=t-e)>0&&this.bitsAvailable?r<>>t))return this.word<<=t,this.bitsAvailable-=t,t;return this.loadWord(),t+this.skipLZ()},e.skipUEG=function(){this.skipBits(1+this.skipLZ())},e.skipEG=function(){this.skipBits(1+this.skipLZ())},e.readUEG=function(){var t=this.skipLZ();return this.readBits(t+1)-1},e.readEG=function(){var t=this.readUEG();return 1&t?1+t>>>1:-1*(t>>>1)},e.readBoolean=function(){return 1===this.readBits(1)},e.readUByte=function(){return this.readBits(8)},e.readUShort=function(){return this.readBits(16)},e.readUInt=function(){return this.readBits(32)},e.skipScalingList=function(t){for(var e=8,r=8,i=0;i=t.length)return void r();if(!(t[e].unit.length<32)){var i=this.decrypter.isSync();if(this.decryptAacSample(t,e,r,i),!i)return}}},e.getAvcEncryptedData=function(t){for(var e=16*Math.floor((t.length-48)/160)+16,r=new Int8Array(e),i=0,a=32;a<=t.length-16;a+=160,i+=16)r.set(t.subarray(a,a+16),i);return r},e.getAvcDecryptedUnit=function(t,e){for(var r=new Uint8Array(e),i=0,a=32;a<=t.length-16;a+=160,i+=16)t.set(r.subarray(i,i+16),a);return t},e.decryptAvcSample=function(t,e,r,i,a,n){var s=q(a.data),o=this.getAvcEncryptedData(s),l=this;this.decryptBuffer(o.buffer,(function(o){a.data=l.getAvcDecryptedUnit(s,o),n||l.decryptAvcSamples(t,e,r+1,i)}))},e.decryptAvcSamples=function(t,e,r,i){if(t instanceof Uint8Array)throw new Error("Cannot decrypt samples of type Uint8Array");for(;;e++,r=0){if(e>=t.length)return void i();for(var a=t[e].units;!(r>=a.length);r++){var n=a[r];if(!(n.data.length<=48||1!==n.type&&5!==n.type)){var s=this.decrypter.isSync();if(this.decryptAvcSample(t,e,r,i,n,s),!s)return}}}},t}(),B={video:1,audio:2,id3:3,text:4},G=function(){function t(t,e,r){this.observer=void 0,this.config=void 0,this.typeSupported=void 0,this.sampleAes=null,this.pmtParsed=!1,this.audioCodec=void 0,this.videoCodec=void 0,this._duration=0,this.aacLastPTS=null,this._initPTS=null,this._initDTS=null,this._pmtId=-1,this._avcTrack=void 0,this._audioTrack=void 0,this._id3Track=void 0,this._txtTrack=void 0,this.aacOverFlow=null,this.avcSample=null,this.remainderData=null,this.observer=t,this.config=e,this.typeSupported=r}t.probe=function(e){var r=t.syncOffset(e);return!(r<0)&&(r&&f.b.warn("MPEG2-TS detected but first sync word found @ offset "+r+", junk ahead ?"),!0)},t.syncOffset=function(t){for(var e=Math.min(1e3,t.length-564),r=0;r>4>1){if((k=A+5+e[A+4])===A+188)continue}else k=A+4;switch(D){case c:R&&(g&&(o=V(g))&&this.parseAVCPES(o,!1),g={data:[],size:0}),g&&(g.data.push(e.subarray(k,A+188)),g.size+=A+188-k);break;case v:R&&(m&&(o=V(m))&&(h.isAAC?this.parseAACPES(o):this.parseMPEGPES(o)),m={data:[],size:0}),m&&(m.data.push(e.subarray(k,A+188)),m.size+=A+188-k);break;case p:R&&(y&&(o=V(y))&&this.parseID3PES(o),y={data:[],size:0}),y&&(y.data.push(e.subarray(k,A+188)),y.size+=A+188-k);break;case 0:R&&(k+=e[k]+1),b=this._pmtId=j(e,k);break;case b:R&&(k+=e[k]+1);var _=H(e,k,!0===this.typeSupported.mpeg||!0===this.typeSupported.mp3,n);(c=_.avc)>0&&(u.pid=c),(v=_.audio)>0&&(h.pid=v,h.isAAC=_.isAAC),(p=_.id3)>0&&(d.pid=p),T&&!E&&(f.b.log("reparse from beginning"),T=!1,A=L-188),E=this.pmtParsed=!0;break;case 17:case 8191:break;default:T=!0}}else this.observer.emit(i.a.ERROR,i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!1,reason:"TS packet did not start with 0x47"});u.pesData=g,h.pesData=m,d.pesData=y;var I={audioTrack:h,avcTrack:u,id3Track:d,textTrack:this._txtTrack};return s&&this.extractRemainingSamples(I),I},e.flush=function(){var t,e=this.remainderData;return this.remainderData=null,t=e?this.demux(e,-1,!1,!0):{audioTrack:this._audioTrack,avcTrack:this._avcTrack,textTrack:this._txtTrack,id3Track:this._id3Track},this.extractRemainingSamples(t),this.sampleAes?this.decrypt(t,this.sampleAes):t},e.extractRemainingSamples=function(t){var e,r=t.audioTrack,i=t.avcTrack,a=t.id3Track,n=i.pesData,s=r.pesData,o=a.pesData;n&&(e=V(n))?(this.parseAVCPES(e,!0),i.pesData=null):i.pesData=n,s&&(e=V(s))?(r.isAAC?this.parseAACPES(e):this.parseMPEGPES(e),r.pesData=null):(null!=s&&s.size&&f.b.log("last AAC PES packet truncated,might overlap between fragments"),r.pesData=s),o&&(e=V(o))?(this.parseID3PES(e),a.pesData=null):a.pesData=o},e.demuxSampleAes=function(t,e,r){var i=this.demux(t,r,!0,!this.config.progressive),a=this.sampleAes=new U(this.observer,this.config,e);return this.decrypt(i,a)},e.decrypt=function(t,e){return new Promise((function(r){var i=t.audioTrack,a=t.avcTrack;i.samples&&i.isAAC?e.decryptAacSamples(i.samples,0,(function(){a.samples?e.decryptAvcSamples(a.samples,0,0,(function(){r(t)})):r(t)})):a.samples&&e.decryptAvcSamples(a.samples,0,0,(function(){r(t)}))}))},e.destroy=function(){this._initPTS=this._initDTS=null,this._duration=0},e.parseAVCPES=function(t,e){var r,i=this,a=this._avcTrack,n=this.parseAVCNALu(t.data),s=this.avcSample,l=!1;t.data=null,s&&n.length&&!a.audFound&&(W(s,a),s=this.avcSample=K(!1,t.pts,t.dts,"")),n.forEach((function(e){switch(e.type){case 1:r=!0,s||(s=i.avcSample=K(!0,t.pts,t.dts,"")),s.frame=!0;var n=e.data;if(l&&n.length>4){var u=new N(n).readSliceType();2!==u&&4!==u&&7!==u&&9!==u||(s.key=!0)}break;case 5:r=!0,s||(s=i.avcSample=K(!0,t.pts,t.dts,"")),s.key=!0,s.frame=!0;break;case 6:r=!0;var h=new N(q(e.data));h.readUByte();for(var d=0,c=0,f=!1,g=0;!f&&h.bytesAvailable>1;){d=0;do{d+=g=h.readUByte()}while(255===g);c=0;do{c+=g=h.readUByte()}while(255===g);if(4===d&&0!==h.bytesAvailable){if(f=!0,181===h.readUByte())if(49===h.readUShort())if(1195456820===h.readUInt())if(3===h.readUByte()){for(var v=h.readUByte(),p=31&v,m=[v,h.readUByte()],y=0;y16){for(var T=[],E=0;E<16;E++)T.push(h.readUByte().toString(16)),3!==E&&5!==E&&7!==E&&9!==E||T.push("-");for(var b=c-16,S=new Uint8Array(b),L=0;L=0){var d={data:t.subarray(u,l-n-1),type:h};o.push(d)}else{var c=this.getLastNalUnit();if(c&&(s&&l<=4-s&&c.state&&(c.data=c.data.subarray(0,c.data.byteLength-s)),(r=l-n-1)>0)){var f=new Uint8Array(c.data.byteLength+r);f.set(c.data,0),f.set(t.subarray(0,r),c.data.byteLength),c.data=f}}l=0&&n>=0){var g={data:t.subarray(u,i),type:h,state:n};o.push(g)}if(0===o.length){var v=this.getLastNalUnit();if(v){var p=new Uint8Array(v.data.byteLength+t.byteLength);p.set(v.data,0),p.set(t,v.data.byteLength),v.data=p}}return a.naluState=n,o},e.parseAACPES=function(t){var e,r,n,s,o=this._audioTrack,l=this.aacLastPTS,u=this.aacOverFlow,h=t.data;if(u){var d=new Uint8Array(u.byteLength+h.byteLength);d.set(u,0),d.set(h,u.byteLength),h=d}for(e=0,r=h.length;e1&&(f.b.log("[tsdemuxer]: AAC: align PTS for overlapping frames by "+Math.round((p-c)/90)),c=p)}for(var y=null;e1;){var l=new Uint8Array(o[0].length+o[1].length);l.set(o[0]),l.set(o[1],o[0].length),o[0]=l,o.splice(1,1)}if(1===((e=o[0])[0]<<16)+(e[1]<<8)+e[2]){if((r=(e[4]<<8)+e[5])&&r>t.size-6)return null;var u=e[7];192&u&&(a=536870912*(14&e[9])+4194304*(255&e[10])+16384*(254&e[11])+128*(255&e[12])+(254&e[13])/2,64&u?a-(n=536870912*(14&e[14])+4194304*(255&e[15])+16384*(254&e[16])+128*(255&e[17])+(254&e[18])/2)>54e5&&(f.b.warn(Math.round((a-n)/9e4)+"s delta between PTS and DTS, align them"),a=n):n=a);var h=(i=e[8])+9;if(t.size<=h)return null;t.size-=h;for(var d=new Uint8Array(t.size),c=0,g=o.length;cv){h-=v;continue}e=e.subarray(h),v-=h,h=0}d.set(e,s),s+=v}return r&&(r-=i+3),{data:d,pts:a,dts:n,len:r}}return null}function W(t,e){if(t.units.length&&t.frame){if(void 0===t.pts){var r=e.samples,i=r.length;if(!i)return void e.dropped++;var a=r[i-1];t.pts=a.pts,t.dts=a.dts}e.samples.push(t)}t.debug.length&&f.b.log(t.pts+"/"+t.dts+":"+t.debug)}function Y(t,e){var r=t.length;if(r>0){if(e.pts>=t[r-1].pts)t.push(e);else for(var i=r-1;i>=0;i--)if(e.pts0?this.lastEndDTS=p:(f.b.warn("Duration parsed from mp4 should be greater than zero"),this.resetNextTimestamp());var m=!!c.audio,y=!!c.video,T="";m&&(T+="audio"),y&&(T+="video");var E={data1:h,startPTS:v,startDTS:v,endPTS:p,endDTS:p,type:T,hasAudio:m,hasVideo:y,nb:1,dropped:0};return u.audio="audio"===E.type?E:void 0,u.video="audio"!==E.type?E:void 0,u.text=i,u.id3=r,u.initSegment=d,u},t}(),et=function(t,e,r){return Object(l.d)(t,e)-r};function rt(t,e){var r=null==t?void 0:t.codec;return r&&r.length>4?r:"hvc1"===r?"hvc1.1.c.L120.90":"av01"===r?"av01.0.04M.08":"avc1"===r||e===Z.a.VIDEO?"avc1.42e01e":"mp4a.40.5"}var it,at=tt,nt=r(12);try{it=self.performance.now.bind(self.performance)}catch(t){f.b.debug("Unable to use Performance API on this environment"),it=self.Date.now}var st=[{demux:X,remux:J.a},{demux:D,remux:at},{demux:A,remux:J.a},{demux:$,remux:J.a}],ot=1024;st.forEach((function(t){var e=t.demux;ot=Math.max(ot,e.minProbeByteLength)}));var lt=function(){function t(t,e,r,i){this.observer=void 0,this.typeSupported=void 0,this.config=void 0,this.vendor=void 0,this.demuxer=void 0,this.remuxer=void 0,this.decrypter=void 0,this.probe=void 0,this.decryptionPromise=null,this.transmuxConfig=void 0,this.currentTransmuxState=void 0,this.cache=new nt.a,this.observer=t,this.typeSupported=e,this.config=r,this.vendor=i}var e=t.prototype;return e.configure=function(t){this.transmuxConfig=t,this.decrypter&&this.decrypter.reset()},e.push=function(t,e,r,i){var a=this,n=r.transmuxing;n.executeStart=it();var s=new Uint8Array(t),o=this.cache,u=this.config,h=this.currentTransmuxState,d=this.transmuxConfig;i&&(this.currentTransmuxState=i);var c=function(t,e){var r=null;t.byteLength>0&&null!=e&&null!=e.key&&null!==e.iv&&null!=e.method&&(r=e);return r}(s,e);if(c&&"AES-128"===c.method){var f=this.getDecrypter();if(!u.enableSoftwareAES)return this.decryptionPromise=f.webCryptoDecrypt(s,c.key.buffer,c.iv.buffer).then((function(t){var e=a.push(t,null,r);return a.decryptionPromise=null,e})),this.decryptionPromise;var g=f.softwareDecrypt(s,c.key.buffer,c.iv.buffer);if(!g)return n.executeEnd=it(),ut(r);s=new Uint8Array(g)}var v=i||h,p=v.contiguous,m=v.discontinuity,y=v.trackSwitch,T=v.accurateTimeOffset,E=v.timeOffset,b=d.audioCodec,S=d.videoCodec,L=d.defaultInitPts,A=d.duration,R=d.initSegmentData;if((m||y)&&this.resetInitSegment(R,b,S,A),m&&this.resetInitialTimestamp(L),p||this.resetContiguity(),this.needsProbing(s,m,y)){if(o.dataLength){var D=o.flush();s=Object(l.a)(D,s)}this.configureTransmuxer(s,d)}var k=this.transmux(s,c,E,T,r),_=this.currentTransmuxState;return _.contiguous=!0,_.discontinuity=!1,_.trackSwitch=!1,n.executeEnd=it(),k},e.flush=function(t){var e=this,r=t.transmuxing;r.executeStart=it();var n=this.decrypter,s=this.cache,o=this.currentTransmuxState,l=this.decryptionPromise;if(l)return l.then((function(){return e.flush(t)}));var u=[],h=o.timeOffset;if(n){var d=n.flush();d&&u.push(this.push(d,null,t))}var c=s.dataLength;s.reset();var f=this.demuxer,g=this.remuxer;if(!f||!g)return c>=ot&&this.observer.emit(i.a.ERROR,i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!0,reason:"no demux matching with content found"}),r.executeEnd=it(),[ut(t)];var v=f.flush(h);return ht(v)?v.then((function(r){return e.flushRemux(u,r,t),u})):(this.flushRemux(u,v,t),u)},e.flushRemux=function(t,e,r){var i=e.audioTrack,a=e.avcTrack,n=e.id3Track,s=e.textTrack,o=this.currentTransmuxState,l=o.accurateTimeOffset,u=o.timeOffset;f.b.log("[transmuxer.ts]: Flushed fragment "+r.sn+(r.part>-1?" p: "+r.part:"")+" of level "+r.level);var h=this.remuxer.remux(i,a,n,s,u,l,!0);t.push({remuxResult:h,chunkMeta:r}),r.transmuxing.executeEnd=it()},e.resetInitialTimestamp=function(t){var e=this.demuxer,r=this.remuxer;e&&r&&(e.resetTimeStamp(t),r.resetTimeStamp(t))},e.resetContiguity=function(){var t=this.demuxer,e=this.remuxer;t&&e&&(t.resetContiguity(),e.resetNextTimestamp())},e.resetInitSegment=function(t,e,r,i){var a=this.demuxer,n=this.remuxer;a&&n&&(a.resetInitSegment(e,r,i),n.resetInitSegment(t,e,r))},e.destroy=function(){this.demuxer&&(this.demuxer.destroy(),this.demuxer=void 0),this.remuxer&&(this.remuxer.destroy(),this.remuxer=void 0)},e.transmux=function(t,e,r,i,a){return e&&"SAMPLE-AES"===e.method?this.transmuxSampleAes(t,e,r,i,a):this.transmuxUnencrypted(t,r,i,a)},e.transmuxUnencrypted=function(t,e,r,i){var a=this.demuxer.demux(t,e,!1,!this.config.progressive),n=a.audioTrack,s=a.avcTrack,o=a.id3Track,l=a.textTrack;return{remuxResult:this.remuxer.remux(n,s,o,l,e,r,!1),chunkMeta:i}},e.transmuxSampleAes=function(t,e,r,i,a){var n=this;return this.demuxer.demuxSampleAes(t,e,r).then((function(t){return{remuxResult:n.remuxer.remux(t.audioTrack,t.avcTrack,t.id3Track,t.textTrack,r,i,!1),chunkMeta:a}}))},e.configureTransmuxer=function(t,e){for(var r,i=this.config,a=this.observer,n=this.typeSupported,s=this.vendor,o=e.audioCodec,l=e.defaultInitPts,u=e.duration,h=e.initSegmentData,d=e.videoCodec,c=0,g=st.length;c>>8^255&p^99,t[f]=p,e[p]=f;var m=c[f],y=c[m],T=c[y],E=257*c[p]^16843008*p;i[f]=E<<24|E>>>8,a[f]=E<<16|E>>>16,n[f]=E<<8|E>>>24,s[f]=E,E=16843009*T^65537*y^257*m^16843008*f,l[p]=E<<24|E>>>8,u[p]=E<<16|E>>>16,h[p]=E<<8|E>>>24,d[p]=E,f?(f=m^c[c[c[T^m]]],g^=c[c[g]]):f=g=1}},e.expandKey=function(t){for(var e=this.uint8ArrayToUint32Array_(t),r=!0,i=0;i1?r-1:0),a=1;a>24&255,o[1]=e>>16&255,o[2]=e>>8&255,o[3]=255&e,o.set(t,4),n=0,e=8;n>24&255,e>>16&255,e>>8&255,255&e,i>>24,i>>16&255,i>>8&255,255&i,a>>24,a>>16&255,a>>8&255,255&a,85,196,0,0]))},t.mdia=function(e){return t.box(t.types.mdia,t.mdhd(e.timescale,e.duration),t.hdlr(e.type),t.minf(e))},t.mfhd=function(e){return t.box(t.types.mfhd,new Uint8Array([0,0,0,0,e>>24,e>>16&255,e>>8&255,255&e]))},t.minf=function(e){return"audio"===e.type?t.box(t.types.minf,t.box(t.types.smhd,t.SMHD),t.DINF,t.stbl(e)):t.box(t.types.minf,t.box(t.types.vmhd,t.VMHD),t.DINF,t.stbl(e))},t.moof=function(e,r,i){return t.box(t.types.moof,t.mfhd(e),t.traf(i,r))},t.moov=function(e){for(var r=e.length,i=[];r--;)i[r]=t.trak(e[r]);return t.box.apply(null,[t.types.moov,t.mvhd(e[0].timescale,e[0].duration)].concat(i).concat(t.mvex(e)))},t.mvex=function(e){for(var r=e.length,i=[];r--;)i[r]=t.trex(e[r]);return t.box.apply(null,[t.types.mvex].concat(i))},t.mvhd=function(e,r){r*=e;var i=Math.floor(r/(n+1)),a=Math.floor(r%(n+1)),s=new Uint8Array([1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,e>>24&255,e>>16&255,e>>8&255,255&e,i>>24,i>>16&255,i>>8&255,255&i,a>>24,a>>16&255,a>>8&255,255&a,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return t.box(t.types.mvhd,s)},t.sdtp=function(e){var r,i,a=e.samples||[],n=new Uint8Array(4+a.length);for(r=0;r>>8&255),n.push(255&a),n=n.concat(Array.prototype.slice.call(i));for(r=0;r>>8&255),s.push(255&a),s=s.concat(Array.prototype.slice.call(i));var o=t.box(t.types.avcC,new Uint8Array([1,n[3],n[4],n[5],255,224|e.sps.length].concat(n).concat([e.pps.length]).concat(s))),l=e.width,u=e.height,h=e.pixelRatio[0],d=e.pixelRatio[1];return t.box(t.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,l>>8&255,255&l,u>>8&255,255&u,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,100,97,105,108,121,109,111,116,105,111,110,47,104,108,115,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,t.box(t.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])),t.box(t.types.pasp,new Uint8Array([h>>24,h>>16&255,h>>8&255,255&h,d>>24,d>>16&255,d>>8&255,255&d])))},t.esds=function(t){var e=t.config.length;return new Uint8Array([0,0,0,0,3,23+e,0,1,0,4,15+e,64,21,0,0,0,0,0,0,0,0,0,0,0,5].concat([e]).concat(t.config).concat([6,1,2]))},t.mp4a=function(e){var r=e.samplerate;return t.box(t.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount,0,16,0,0,0,0,r>>8&255,255&r,0,0]),t.box(t.types.esds,t.esds(e)))},t.mp3=function(e){var r=e.samplerate;return t.box(t.types[".mp3"],new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount,0,16,0,0,0,0,r>>8&255,255&r,0,0]))},t.stsd=function(e){return"audio"===e.type?e.isAAC||"mp3"!==e.codec?t.box(t.types.stsd,t.STSD,t.mp4a(e)):t.box(t.types.stsd,t.STSD,t.mp3(e)):t.box(t.types.stsd,t.STSD,t.avc1(e))},t.tkhd=function(e){var r=e.id,i=e.duration*e.timescale,a=e.width,s=e.height,o=Math.floor(i/(n+1)),l=Math.floor(i%(n+1));return t.box(t.types.tkhd,new Uint8Array([1,0,0,7,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,r>>24&255,r>>16&255,r>>8&255,255&r,0,0,0,0,o>>24,o>>16&255,o>>8&255,255&o,l>>24,l>>16&255,l>>8&255,255&l,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,a>>8&255,255&a,0,0,s>>8&255,255&s,0,0]))},t.traf=function(e,r){var i=t.sdtp(e),a=e.id,s=Math.floor(r/(n+1)),o=Math.floor(r%(n+1));return t.box(t.types.traf,t.box(t.types.tfhd,new Uint8Array([0,0,0,0,a>>24,a>>16&255,a>>8&255,255&a])),t.box(t.types.tfdt,new Uint8Array([1,0,0,0,s>>24,s>>16&255,s>>8&255,255&s,o>>24,o>>16&255,o>>8&255,255&o])),t.trun(e,i.length+16+20+8+16+8+8),i)},t.trak=function(e){return e.duration=e.duration||4294967295,t.box(t.types.trak,t.tkhd(e),t.mdia(e))},t.trex=function(e){var r=e.id;return t.box(t.types.trex,new Uint8Array([0,0,0,0,r>>24,r>>16&255,r>>8&255,255&r,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))},t.trun=function(e,r){var i,a,n,s,o,l,u=e.samples||[],h=u.length,d=12+16*h,c=new Uint8Array(d);for(r+=8+d,c.set([0,0,15,1,h>>>24&255,h>>>16&255,h>>>8&255,255&h,r>>>24&255,r>>>16&255,r>>>8&255,255&r],0),i=0;i>>24&255,n>>>16&255,n>>>8&255,255&n,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,l>>>24&255,l>>>16&255,l>>>8&255,255&l],12+16*i);return t.box(t.types.trun,c)},t.initSegment=function(e){t.types||t.init();var r=t.moov(e),i=new Uint8Array(t.FTYP.byteLength+r.byteLength);return i.set(t.FTYP),i.set(r,t.FTYP.byteLength),i},t}();s.types=void 0,s.HDLR_TYPES=void 0,s.STTS=void 0,s.STSC=void 0,s.STCO=void 0,s.STSZ=void 0,s.VMHD=void 0,s.SMHD=void 0,s.STSD=void 0,s.FTYP=void 0,s.DINF=void 0;var o=s,l=r(0),u=r(2),h=r(1),d=r(7);function c(){return(c=Object.assign||function(t){for(var e=1;e0?t:r.pts}),t[0].pts);return e&&h.b.debug("PTS rollover detected"),r},e.remux=function(t,e,r,i,a,n,s){var o,l,u,d,c,f,g=a,v=a,p=t.pid>-1,y=e.pid>-1,T=t.samples.length>0,E=e.samples.length>1;if((!p||T)&&(!y||E)||this.ISGenerated||s){this.ISGenerated||(u=this.generateIS(t,e,a));var b=this.isVideoContiguous;if(E&&!b&&this.config.forceKeyFrameOnDiscontinuity){var S=e.samples.length,L=function(t){for(var e=0;e0){h.b.warn("[mp4-remuxer]: Dropped "+L+" out of "+S+" video samples due to a missing keyframe");var A=this.getVideoStartPts(e.samples);e.samples=e.samples.slice(L),e.dropped+=L,v+=(e.samples[0].pts-A)/(e.timescale||9e4)}else-1===L&&(h.b.warn("[mp4-remuxer]: No keyframe found out of "+S+" video samples"),f=!1)}if(this.ISGenerated){if(T&&E){var R=this.getVideoStartPts(e.samples),D=(m(t.samples[0].pts,R)-R)/e.inputTimeScale;g+=Math.max(0,D),v+=Math.max(0,-D)}if(T){if(t.samplerate||(h.b.warn("[mp4-remuxer]: regenerate InitSegment as audio detected"),delete(u=this.generateIS(t,e,a)).video),l=this.remuxAudio(t,g,this.isAudioContiguous,n,E?v:void 0),E){var k=l?l.endPTS-l.startPTS:0;e.inputTimeScale||(h.b.warn("[mp4-remuxer]: regenerate InitSegment as video detected"),u=this.generateIS(t,e,a)),o=this.remuxVideo(e,v,b,k)}}else E&&(o=this.remuxVideo(e,v,b,0));o&&void 0!==f&&(o.independent=f)}}return this.ISGenerated&&(r.samples.length&&(c=this.remuxID3(r,a)),i.samples.length&&(d=this.remuxText(i,a))),{audio:l,video:o,initSegment:u,independent:f,text:d,id3:c}},e.generateIS=function(t,e,r){var a,n,s,l=t.samples,u=e.samples,h=this.typeSupported,d={},c=!Object(i.a)(this._initPTS),f="audio/mp4";if(c&&(a=n=1/0),t.config&&l.length&&(t.timescale=t.samplerate,t.isAAC||(h.mpeg?(f="audio/mpeg",t.codec=""):h.mp3&&(t.codec="mp3")),d.audio={id:"audio",container:f,codec:t.codec,initSegment:!t.isAAC&&h.mpeg?new Uint8Array(0):o.initSegment([t]),metadata:{channelCount:t.channelCount}},c&&(s=t.inputTimeScale,a=n=l[0].pts-Math.round(s*r))),e.sps&&e.pps&&u.length&&(e.timescale=e.inputTimeScale,d.video={id:"main",container:"video/mp4",codec:e.codec,initSegment:o.initSegment([e]),metadata:{width:e.width,height:e.height}},c)){s=e.inputTimeScale;var g=this.getVideoStartPts(u),v=Math.round(s*r);n=Math.min(n,m(u[0].dts,g)-v),a=Math.min(a,g-v)}if(Object.keys(d).length)return this.ISGenerated=!0,c&&(this._initPTS=a,this._initDTS=n),{tracks:d,initPTS:a,timescale:s}},e.remuxVideo=function(t,e,r,i){var a,n,s,g=t.inputTimeScale,p=t.samples,T=[],E=p.length,b=this._initPTS,S=this.nextAvcDts,L=8,A=Number.POSITIVE_INFINITY,R=Number.NEGATIVE_INFINITY,D=0,k=!1;r&&null!==S||(S=e*g-(p[0].pts-m(p[0].dts,p[0].pts)));for(var _=0;_I.pts){D=Math.max(Math.min(D,I.pts-I.dts),-18e3)}I.dts0?_-1:_].dts&&(k=!0)}k&&p.sort((function(t,e){var r=t.dts-e.dts,i=t.pts-e.pts;return r||i})),n=p[0].dts,s=p[p.length-1].dts;var C=Math.round((s-n)/(E-1));if(D<0){if(D<-2*C){h.b.warn("PTS < DTS detected in video samples, offsetting DTS from PTS by "+Object(d.b)(-C,!0)+" ms");for(var w=D,O=0;OC;if(M||P<-1){M?h.b.warn("AVC: "+Object(d.b)(P,!0)+" ms ("+P+"dts) hole between fragments detected, filling it"):h.b.warn("AVC: "+Object(d.b)(-P,!0)+" ms ("+P+"dts) overlapping between fragments detected"),n=S;var F=p[0].pts-P;p[0].dts=n,p[0].pts=F,h.b.log("Video: First PTS/DTS adjusted: "+Object(d.b)(F,!0)+"/"+Object(d.b)(n,!0)+", delta: "+Object(d.b)(P,!0)+" ms")}}v&&(n=Math.max(0,n));for(var N=0,U=0,B=0;B0?X-1:X].dts;if(it.stretchShortVideoTrack&&null!==this.nextAudioPts){var nt=Math.floor(it.maxBufferHole*g),st=(i?A+i*g:this.nextAudioPts)-z.pts;st>nt?((a=st-at)<0&&(a=at),h.b.log("[mp4-remuxer]: It is approximately "+st/90+" ms to the next segment; using duration "+a/90+" ms for the last video frame.")):a=at}else a=at}var ot=Math.round(z.pts-z.dts);T.push(new y(z.key,a,$,ot))}if(T.length&&f&&f<70){var lt=T[0].flags;lt.dependsOn=2,lt.isNonSync=0}this.nextAvcDts=S=s+a,this.isVideoContiguous=!0;var ut={data1:o.moof(t.sequenceNumber++,n,c({},t,{samples:T})),data2:W,startPTS:A/g,endPTS:(R+a)/g,startDTS:n/g,endDTS:S/g,type:"video",hasAudio:!1,hasVideo:!0,nb:T.length,dropped:t.dropped};return t.samples=[],t.dropped=0,ut},e.remuxAudio=function(t,e,r,i,n){var s,d=t.inputTimeScale,f=d/(t.samplerate?t.samplerate:d),g=t.isAAC?1024:1152,v=g*f,p=this._initPTS,T=!t.isAAC&&this.typeSupported.mpeg,E=[],b=t.samples,S=T?0:8,L=this.nextAudioPts||-1,A=e*d;if(this.isAudioContiguous=r=r||b.length&&L>0&&(i&&Math.abs(A-L)<9e3||Math.abs(m(b[0].pts-p,A)-L)<20*v),b.forEach((function(t){t.pts=t.dts=m(t.pts-p,A)})),!r||L<0){if(!(b=b.filter((function(t){return t.pts>=0}))).length)return;L=0===n?0:i?Math.max(0,A):b[0].pts}if(t.isAAC)for(var R=this.config.maxAudioFramesDrift,D=0,k=L;D0?(h.b.warn("[mp4-remuxer]: Dropping 1 audio frame @ "+(k/d).toFixed(3)+"s due to "+Math.round(w)+" ms overlap."),b.splice(D,1)):(h.b.warn("Audio frame @ "+(I/d).toFixed(3)+"s overlaps nextAudioPts by "+Math.round(1e3*C/d)+" ms."),k=I+v,D++);else if(C>=R*v&&w<1e4&&void 0!==n){var O=Math.floor(C/v);k=I-O*v,h.b.warn("[mp4-remuxer]: Injecting "+O+" audio frame @ "+(k/d).toFixed(3)+"s due to "+Math.round(1e3*C/d)+" ms gap.");for(var x=0;x0&&W<1e4)Y=Math.round((V-L)/v),h.b.log("[mp4-remuxer]: "+W+" ms hole between AAC samples detected,filling it"),Y>0&&((s=a.getSilentFrame(t.manifestCodec||t.codec,t.channelCount))||(s=H.subarray()),U+=Y*s.length);else if(W<-12){h.b.log("[mp4-remuxer]: drop overlapping AAC sample, expected/parsed/delta:"+(L/d).toFixed(3)+"s/"+(V/d).toFixed(3)+"s/"+-W+"ms"),U-=H.byteLength;continue}V=L}if(F=V,!(U>0))return;U+=S;try{M=new Uint8Array(U)}catch(t){return void this.observer.emit(l.a.ERROR,l.a.ERROR,{type:u.b.MUX_ERROR,details:u.a.REMUX_ALLOC_ERROR,fatal:!1,bytes:U,reason:"fail allocating audio mdat "+U})}T||(new DataView(M.buffer).setUint32(0,U),M.set(o.types.mdat,4));for(var q=0;q4294967296;)t+=r;return t}var y=function(t,e,r,i){this.size=void 0,this.duration=void 0,this.cts=void 0,this.flags=void 0,this.duration=e,this.size=r,this.cts=i,this.flags=new T(t)},T=function(t){this.isLeading=0,this.isDependedOn=0,this.hasRedundancy=0,this.degradPrio=0,this.dependsOn=1,this.isNonSync=1,this.dependsOn=t?2:1,this.isNonSync=t?0:1}},function(t,e,r){"use strict";r.d(e,"a",(function(){return n}));var i=r(10);function a(t,e){for(var r=0;r0}),!1)}t.exports=function(t,e){e=e||{};var a={main:r.m},o=e.all?{main:Object.keys(a.main)}:function(t,e){for(var r={main:[e]},i={main:[]},a={main:{}};s(r);)for(var o=Object.keys(r),l=0;lt.endSN||e>0||0===e&&r>0,this.updated||this.advanced?this.misses=Math.floor(.6*t.misses):this.misses=t.misses+1,this.availabilityDelay=t.availabilityDelay},e=t,(r=[{key:"hasProgramDateTime",get:function(){return!!this.fragments.length&&Object(a.a)(this.fragments[this.fragments.length-1].programDateTime)}},{key:"levelTargetDuration",get:function(){return this.averagetargetduration||this.targetduration||10}},{key:"drift",get:function(){var t=this.driftEndTime-this.driftStartTime;return t>0?1e3*(this.driftEnd-this.driftStart)/t:1}},{key:"edge",get:function(){return this.partEnd||this.fragmentEnd}},{key:"partEnd",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].end:this.fragmentEnd}},{key:"fragmentEnd",get:function(){var t;return null!==(t=this.fragments)&&void 0!==t&&t.length?this.fragments[this.fragments.length-1].end:0}},{key:"age",get:function(){return this.advancedDateTime?Math.max(Date.now()-this.advancedDateTime,0)/1e3:0}},{key:"lastPartIndex",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].index:-1}},{key:"lastPartSn",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].fragment.sn:this.endSN}}])&&h(e.prototype,r),i&&h(e,i),t}(),c=r(16),f=/^(\d+)x(\d+)$/,g=/\s*(.+?)\s*=((?:\".*?\")|.*?)(?:,|$)/g,v=function(){function t(e){for(var r in"string"==typeof e&&(e=t.parseAttrList(e)),e)e.hasOwnProperty(r)&&(this[r]=e[r])}var e=t.prototype;return e.decimalInteger=function(t){var e=parseInt(this[t],10);return e>Number.MAX_SAFE_INTEGER?1/0:e},e.hexadecimalInteger=function(t){if(this[t]){var e=(this[t]||"0x").slice(2);e=(1&e.length?"0":"")+e;for(var r=new Uint8Array(e.length/2),i=0;iNumber.MAX_SAFE_INTEGER?1/0:e},e.decimalFloatingPoint=function(t){return parseFloat(this[t])},e.optionalFloat=function(t,e){var r=this[t];return r?parseFloat(r):e},e.enumeratedString=function(t){return this[t]},e.bool=function(t){return"YES"===this[t]},e.decimalResolution=function(t){var e=f.exec(this[t]);if(null!==e)return{width:parseInt(e[1],10),height:parseInt(e[2],10)}},t.parseAttrList=function(t){var e,r={};for(g.lastIndex=0;null!==(e=g.exec(t));){var i=e[2];0===i.indexOf('"')&&i.lastIndexOf('"')===i.length-1&&(i=i.slice(1,-1)),r[e[1]]=i}return r},t}(),p={audio:{a3ds:!0,"ac-3":!0,"ac-4":!0,alac:!0,alaw:!0,dra1:!0,"dts+":!0,"dts-":!0,dtsc:!0,dtse:!0,dtsh:!0,"ec-3":!0,enca:!0,g719:!0,g726:!0,m4ae:!0,mha1:!0,mha2:!0,mhm1:!0,mhm2:!0,mlpa:!0,mp4a:!0,"raw ":!0,Opus:!0,samr:!0,sawb:!0,sawp:!0,sevc:!0,sqcp:!0,ssmv:!0,twos:!0,ulaw:!0},video:{avc1:!0,avc2:!0,avc3:!0,avc4:!0,avcp:!0,av01:!0,drac:!0,dvav:!0,dvhe:!0,encv:!0,hev1:!0,hvc1:!0,mjp2:!0,mp4v:!0,mvc1:!0,mvc2:!0,mvc3:!0,mvc4:!0,resv:!0,rv60:!0,s263:!0,svc1:!0,svc2:!0,"vc-1":!0,vp08:!0,vp09:!0},text:{stpp:!0,wvtt:!0}};function m(t,e){return MediaSource.isTypeSupported((e||"video")+'/mp4;codecs="'+t+'"')}var y=/#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-SESSION-DATA:([^\r\n]*)[\r\n]+/g,T=/#EXT-X-MEDIA:(.*)/g,E=new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source,/(?!#) *(\S[\S ]*)/.source,/#EXT-X-BYTERANGE:*(.+)/.source,/#EXT-X-PROGRAM-DATE-TIME:(.+)/.source,/#.*/.source].join("|"),"g"),b=new RegExp([/#(EXTM3U)/.source,/#EXT-X-(PLAYLIST-TYPE):(.+)/.source,/#EXT-X-(MEDIA-SEQUENCE): *(\d+)/.source,/#EXT-X-(SKIP):(.+)/.source,/#EXT-X-(TARGETDURATION): *(\d+)/.source,/#EXT-X-(KEY):(.+)/.source,/#EXT-X-(START):(.+)/.source,/#EXT-X-(ENDLIST)/.source,/#EXT-X-(DISCONTINUITY-SEQ)UENCE: *(\d+)/.source,/#EXT-X-(DIS)CONTINUITY/.source,/#EXT-X-(VERSION):(\d+)/.source,/#EXT-X-(MAP):(.+)/.source,/#EXT-X-(SERVER-CONTROL):(.+)/.source,/#EXT-X-(PART-INF):(.+)/.source,/#EXT-X-(GAP)/.source,/#EXT-X-(BITRATE):\s*(\d+)/.source,/#EXT-X-(PART):(.+)/.source,/#EXT-X-(PRELOAD-HINT):(.+)/.source,/#EXT-X-(RENDITION-REPORT):(.+)/.source,/(#)([^:]*):(.*)/.source,/(#)(.*)(?:.*)\r?\n?/.source].join("|")),S=/\.(mp4|m4s|m4v|m4a)$/i;var L,A,R=function(){function t(){}return t.findGroup=function(t,e){for(var r=0;r2){var r=e.shift()+".";return r+=parseInt(e.shift()).toString(16),r+=("000"+parseInt(e.shift()).toString(16)).substr(-4)}return t},t.resolve=function(t,e){return i.buildAbsoluteURL(e,t,{alwaysNormalize:!0})},t.parseMasterPlaylist=function(e,r){var i,a=[],n={},s=!1;for(y.lastIndex=0;null!=(i=y.exec(e));)if(i[1]){var o=new v(i[1]),l={attrs:o,bitrate:o.decimalInteger("AVERAGE-BANDWIDTH")||o.decimalInteger("BANDWIDTH"),name:o.NAME,url:t.resolve(i[2],r)},u=o.decimalResolution("RESOLUTION");u&&(l.width=u.width,l.height=u.height),D((o.CODECS||"").split(/[ ,]+/).filter((function(t){return t})),l),l.videoCodec&&-1!==l.videoCodec.indexOf("avc1")&&(l.videoCodec=t.convertAVC1ToAVCOTI(l.videoCodec)),a.push(l)}else if(i[3]){var h=new v(i[3]);h["DATA-ID"]&&(s=!0,n[h["DATA-ID"]]=h)}return{levels:a,sessionData:s?n:null}},t.parseMasterPlaylistMedia=function(e,r,i,a){var n;void 0===a&&(a=[]);var s=[],o=0;for(T.lastIndex=0;null!==(n=T.exec(e));){var l=new v(n[1]);if(l.TYPE===i){var u={attrs:l,bitrate:0,id:o++,groupId:l["GROUP-ID"],instreamId:l["INSTREAM-ID"],name:l.NAME||l.LANGUAGE||"",type:i,default:l.bool("DEFAULT"),autoselect:l.bool("AUTOSELECT"),forced:l.bool("FORCED"),lang:l.LANGUAGE,url:l.URI?t.resolve(l.URI,r):""};if(a.length){var h=t.findGroup(a,u.groupId)||a[0];k(u,h,"audioCodec"),k(u,h,"textCodec")}s.push(u)}}return s},t.parseLevelPlaylist=function(t,e,r,n,s){var l,h,f,g=new d(e),p=g.fragments,m=0,y=0,T=0,L=0,A=null,R=new u.b(n,e),D=-1;for(E.lastIndex=0,g.m3u8=t;null!==(l=E.exec(t));){var k=l[1];if(k){R.duration=parseFloat(k);var I=(" "+l[2]).slice(1);R.title=I||null,R.tagList.push(I?["INF",k,I]:["INF",k])}else if(l[3])Object(a.a)(R.duration)&&(R.start=T,f&&(R.levelkey=f),R.sn=m,R.level=r,R.cc=L,R.urlId=s,p.push(R),R.relurl=(" "+l[3]).slice(1),_(R,A),A=R,T+=R.duration,m++,y=0,(R=new u.b(n,e)).start=T,R.sn=m,R.cc=L,R.level=r);else if(l[4]){var C=(" "+l[4]).slice(1);A?R.setByteRange(C,A):R.setByteRange(C)}else if(l[5])R.rawProgramDateTime=(" "+l[5]).slice(1),R.tagList.push(["PROGRAM-DATE-TIME",R.rawProgramDateTime]),-1===D&&(D=p.length);else{if(!(l=l[0].match(b))){o.b.warn("No matches on slow regex match for level playlist!");continue}for(h=1;h-1){o.b.warn("Keyformat "+W+" is not supported from the manifest");continue}if("identity"!==W)continue;G&&(f=c.a.fromURL(e,K),K&&["AES-128","SAMPLE-AES","SAMPLE-AES-CENC"].indexOf(G)>=0&&(f.method=G,f.keyFormat=W,V&&(f.keyID=V),H&&(f.keyFormatVersions=H),f.iv=j));break;case"START":var Y=new v(O).decimalFloatingPoint("TIME-OFFSET");Object(a.a)(Y)&&(g.startTimeOffset=Y);break;case"MAP":var q=new v(O);R.relurl=q.URI,q.BYTERANGE&&R.setByteRange(q.BYTERANGE),R.level=r,R.sn="initSegment",f&&(R.levelkey=f),g.initSegment=R,(R=new u.b(n,e)).rawProgramDateTime=g.initSegment.rawProgramDateTime;break;case"SERVER-CONTROL":var X=new v(O);g.canBlockReload=X.bool("CAN-BLOCK-RELOAD"),g.canSkipUntil=X.optionalFloat("CAN-SKIP-UNTIL",0),g.canSkipDateRanges=g.canSkipUntil>0&&X.bool("CAN-SKIP-DATERANGES"),g.partHoldBack=X.optionalFloat("PART-HOLD-BACK",0),g.holdBack=X.optionalFloat("HOLD-BACK",0);break;case"PART-INF":var z=new v(O);g.partTarget=z.decimalFloatingPoint("PART-TARGET");break;case"PART":var Q=g.partList;Q||(Q=g.partList=[]);var $=y>0?Q[Q.length-1]:void 0,J=y++,Z=new u.c(new v(O),R,e,J,$);Q.push(Z),R.duration+=Z.duration;break;case"PRELOAD-HINT":var tt=new v(O);g.preloadHint=tt;break;case"RENDITION-REPORT":var et=new v(O);g.renditionReports=g.renditionReports||[],g.renditionReports.push(et);break;default:o.b.warn("line parsed but not handled: "+l)}}}A&&!A.relurl?(p.pop(),T-=A.duration,g.partList&&(g.fragmentHint=A)):g.partList&&(_(R,A),R.cc=L,g.fragmentHint=R);var rt=p.length,it=p[0],at=p[rt-1];if((T+=g.skippedSegments*g.targetduration)>0&&rt&&at){g.averagetargetduration=T/rt;var nt=at.sn;g.endSN="initSegment"!==nt?nt:0,it&&(g.startCC=it.cc,g.initSegment||g.fragments.every((function(t){return t.relurl&&(e=t.relurl,S.test(null!=(r=null===(a=i.parseURL(e))||void 0===a?void 0:a.path)?r:""));var e,r,a}))&&(o.b.warn("MP4 fragments found but no init segment (probably no MAP, incomplete M3U8), trying to fetch SIDX"),(R=new u.b(n,e)).relurl=at.relurl,R.level=r,R.sn="initSegment",g.initSegment=R,g.needSidxRanges=!0))}else g.endSN=0,g.startCC=0;return g.fragmentHint&&(T+=g.fragmentHint.duration),g.totalduration=T,g.endCC=L,D>0&&function(t,e){for(var r=t[e],i=e;i--;){var a=t[i];if(!a)return;a.programDateTime=r.programDateTime-1e3*a.duration,r=a}}(p,D),g},t}();function D(t,e){["video","audio","text"].forEach((function(r){var i=t.filter((function(t){return function(t,e){var r=p[e];return!!r&&!0===r[t.slice(0,4)]}(t,r)}));if(i.length){var a=i.filter((function(t){return 0===t.lastIndexOf("avc1",0)||0===t.lastIndexOf("mp4a",0)}));e[r+"Codec"]=a.length>0?a[0]:i[0],t=t.filter((function(t){return-1===i.indexOf(t)}))}})),e.unknownCodecs=t}function k(t,e,r){var i=e[r];i&&(t[r]=i)}function _(t,e){t.rawProgramDateTime?t.programDateTime=Date.parse(t.rawProgramDateTime):null!=e&&e.programDateTime&&(t.programDateTime=e.endProgramDateTime),Object(a.a)(t.programDateTime)||(t.programDateTime=null,t.rawProgramDateTime=null)}function I(t,e){var r=t.url;return void 0!==r&&0!==r.indexOf("data:")||(r=e.url),r}!function(t){t.MANIFEST="manifest",t.LEVEL="level",t.AUDIO_TRACK="audioTrack",t.SUBTITLE_TRACK="subtitleTrack"}(L||(L={})),function(t){t.MAIN="main",t.AUDIO="audio",t.SUBTITLE="subtitle"}(A||(A={}));var C=function(){function t(t){this.hls=void 0,this.loaders=Object.create(null),this.hls=t,this.registerListeners()}var e=t.prototype;return e.registerListeners=function(){var t=this.hls;t.on(n.a.MANIFEST_LOADING,this.onManifestLoading,this),t.on(n.a.LEVEL_LOADING,this.onLevelLoading,this),t.on(n.a.AUDIO_TRACK_LOADING,this.onAudioTrackLoading,this),t.on(n.a.SUBTITLE_TRACK_LOADING,this.onSubtitleTrackLoading,this)},e.unregisterListeners=function(){var t=this.hls;t.off(n.a.MANIFEST_LOADING,this.onManifestLoading,this),t.off(n.a.LEVEL_LOADING,this.onLevelLoading,this),t.off(n.a.AUDIO_TRACK_LOADING,this.onAudioTrackLoading,this),t.off(n.a.SUBTITLE_TRACK_LOADING,this.onSubtitleTrackLoading,this)},e.createInternalLoader=function(t){var e=this.hls.config,r=e.pLoader,i=e.loader,a=new(r||i)(e);return t.loader=a,this.loaders[t.type]=a,a},e.getInternalLoader=function(t){return this.loaders[t.type]},e.resetInternalLoader=function(t){this.loaders[t]&&delete this.loaders[t]},e.destroyInternalLoaders=function(){for(var t in this.loaders){var e=this.loaders[t];e&&e.destroy(),this.resetInternalLoader(t)}},e.destroy=function(){this.unregisterListeners(),this.destroyInternalLoaders()},e.onManifestLoading=function(t,e){var r=e.url;this.load({id:null,groupId:null,level:0,responseType:"text",type:L.MANIFEST,url:r,deliveryDirectives:null})},e.onLevelLoading=function(t,e){var r=e.id,i=e.level,a=e.url,n=e.deliveryDirectives;this.load({id:r,groupId:null,level:i,responseType:"text",type:L.LEVEL,url:a,deliveryDirectives:n})},e.onAudioTrackLoading=function(t,e){var r=e.id,i=e.groupId,a=e.url,n=e.deliveryDirectives;this.load({id:r,groupId:i,level:null,responseType:"text",type:L.AUDIO_TRACK,url:a,deliveryDirectives:n})},e.onSubtitleTrackLoading=function(t,e){var r=e.id,i=e.groupId,a=e.url,n=e.deliveryDirectives;this.load({id:r,groupId:i,level:null,responseType:"text",type:L.SUBTITLE_TRACK,url:a,deliveryDirectives:n})},e.load=function(t){var e,r,i,a,n,s,l=this.hls.config,u=this.getInternalLoader(t);if(u){var h=u.context;if(h&&h.url===t.url)return void o.b.trace("[playlist-loader]: playlist request ongoing");o.b.log("[playlist-loader]: aborting previous loader for type: "+t.type),u.abort()}switch(t.type){case L.MANIFEST:r=l.manifestLoadingMaxRetry,i=l.manifestLoadingTimeOut,a=l.manifestLoadingRetryDelay,n=l.manifestLoadingMaxRetryTimeout;break;case L.LEVEL:case L.AUDIO_TRACK:case L.SUBTITLE_TRACK:r=0,i=l.levelLoadingTimeOut;break;default:r=l.levelLoadingMaxRetry,i=l.levelLoadingTimeOut,a=l.levelLoadingRetryDelay,n=l.levelLoadingMaxRetryTimeout}if((u=this.createInternalLoader(t),null!==(e=t.deliveryDirectives)&&void 0!==e&&e.part)&&(t.type===L.LEVEL&&null!==t.level?s=this.hls.levels[t.level].details:t.type===L.AUDIO_TRACK&&null!==t.id?s=this.hls.audioTracks[t.id].details:t.type===L.SUBTITLE_TRACK&&null!==t.id&&(s=this.hls.subtitleTracks[t.id].details),s)){var d=s.partTarget,c=s.targetduration;d&&c&&(i=Math.min(1e3*Math.max(3*d,.8*c),i))}var f={timeout:i,maxRetry:r,retryDelay:a,maxRetryDelay:n,highWaterMark:0},g={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};u.load(t,f,g)},e.loadsuccess=function(t,e,r,i){if(void 0===i&&(i=null),r.isSidxRequest)return this.handleSidxRequest(t,r),void this.handlePlaylistLoaded(t,e,r,i);this.resetInternalLoader(r.type);var a=t.data;0===a.indexOf("#EXTM3U")?(e.parsing.start=performance.now(),a.indexOf("#EXTINF:")>0||a.indexOf("#EXT-X-TARGETDURATION:")>0?this.handleTrackOrLevelPlaylist(t,e,r,i):this.handleMasterPlaylist(t,e,r,i)):this.handleManifestParsingError(t,r,"no EXTM3U delimiter",i)},e.loaderror=function(t,e,r){void 0===r&&(r=null),this.handleNetworkError(e,r,!1,t)},e.loadtimeout=function(t,e,r){void 0===r&&(r=null),this.handleNetworkError(e,r,!0)},e.handleMasterPlaylist=function(t,e,r,i){var a=this.hls,s=t.data,l=I(t,r),u=R.parseMasterPlaylist(s,l),h=u.levels,d=u.sessionData;if(h.length){var c=h.map((function(t){return{id:t.attrs.AUDIO,audioCodec:t.audioCodec}})),f=h.map((function(t){return{id:t.attrs.SUBTITLES,textCodec:t.textCodec}})),g=R.parseMasterPlaylistMedia(s,l,"AUDIO",c),p=R.parseMasterPlaylistMedia(s,l,"SUBTITLES",f),m=R.parseMasterPlaylistMedia(s,l,"CLOSED-CAPTIONS");if(g.length)g.some((function(t){return!t.url}))||!h[0].audioCodec||h[0].attrs.AUDIO||(o.b.log("[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one"),g.unshift({type:"main",name:"main",default:!1,autoselect:!1,forced:!1,id:-1,attrs:new v({}),bitrate:0,url:""}));a.trigger(n.a.MANIFEST_LOADED,{levels:h,audioTracks:g,subtitles:p,captions:m,url:l,stats:e,networkDetails:i,sessionData:d})}else this.handleManifestParsingError(t,r,"no level found in manifest",i)},e.handleTrackOrLevelPlaylist=function(t,e,r,i){var o=this.hls,l=r.id,u=r.level,h=r.type,d=I(t,r),c=Object(a.a)(l)?l:0,f=Object(a.a)(u)?u:c,g=function(t){switch(t.type){case L.AUDIO_TRACK:return A.AUDIO;case L.SUBTITLE_TRACK:return A.SUBTITLE;default:return A.MAIN}}(r),p=R.parseLevelPlaylist(t.data,d,f,g,c);if(p.fragments.length){if(h===L.MANIFEST){var m={attrs:new v({}),bitrate:0,details:p,name:"",url:d};o.trigger(n.a.MANIFEST_LOADED,{levels:[m],audioTracks:[],url:d,stats:e,networkDetails:i,sessionData:null})}if(e.parsing.end=performance.now(),p.needSidxRanges){var y=p.initSegment.url;this.load({url:y,isSidxRequest:!0,type:h,level:u,levelDetails:p,id:l,groupId:null,rangeStart:0,rangeEnd:2048,responseType:"arraybuffer",deliveryDirectives:null})}else r.levelDetails=p,this.handlePlaylistLoaded(t,e,r,i)}else o.trigger(n.a.ERROR,{type:s.b.NETWORK_ERROR,details:s.a.LEVEL_EMPTY_ERROR,fatal:!1,url:d,reason:"no fragments found in level",level:"number"==typeof r.level?r.level:void 0})},e.handleSidxRequest=function(t,e){var r=Object(l.g)(new Uint8Array(t.data));if(r){var i=r.references,a=e.levelDetails;i.forEach((function(t,e){var r=t.info,i=a.fragments[e];0===i.byteRange.length&&i.setByteRange(String(1+r.end-r.start)+"@"+String(r.start))})),a.initSegment.setByteRange(String(r.moovEndOffset)+"@0")}},e.handleManifestParsingError=function(t,e,r,i){this.hls.trigger(n.a.ERROR,{type:s.b.NETWORK_ERROR,details:s.a.MANIFEST_PARSING_ERROR,fatal:e.type===L.MANIFEST,url:t.url,reason:r,response:t,context:e,networkDetails:i})},e.handleNetworkError=function(t,e,r,i){void 0===r&&(r=!1),o.b.warn("[playlist-loader]: A network "+(r?"timeout":"error")+" occurred while loading "+t.type+" level: "+t.level+" id: "+t.id+' group-id: "'+t.groupId+'"');var a=s.a.UNKNOWN,l=!1,u=this.getInternalLoader(t);switch(t.type){case L.MANIFEST:a=r?s.a.MANIFEST_LOAD_TIMEOUT:s.a.MANIFEST_LOAD_ERROR,l=!0;break;case L.LEVEL:a=r?s.a.LEVEL_LOAD_TIMEOUT:s.a.LEVEL_LOAD_ERROR,l=!1;break;case L.AUDIO_TRACK:a=r?s.a.AUDIO_TRACK_LOAD_TIMEOUT:s.a.AUDIO_TRACK_LOAD_ERROR,l=!1;break;case L.SUBTITLE_TRACK:a=r?s.a.SUBTITLE_TRACK_LOAD_TIMEOUT:s.a.SUBTITLE_LOAD_ERROR,l=!1}u&&this.resetInternalLoader(t.type);var h={type:s.b.NETWORK_ERROR,details:a,fatal:l,url:t.url,loader:u,context:t,networkDetails:e};i&&(h.response=i),this.hls.trigger(n.a.ERROR,h)},e.handlePlaylistLoaded=function(t,e,r,i){var a=r.type,s=r.level,o=r.id,l=r.groupId,u=r.loader,h=r.levelDetails,d=r.deliveryDirectives;if(null!=h&&h.targetduration){if(u)switch(h.live&&(u.getCacheAge&&(h.ageHeader=u.getCacheAge()||0),u.getCacheAge&&!isNaN(h.ageHeader)||(h.ageHeader=0)),a){case L.MANIFEST:case L.LEVEL:this.hls.trigger(n.a.LEVEL_LOADED,{details:h,level:s||0,id:o||0,stats:e,networkDetails:i,deliveryDirectives:d});break;case L.AUDIO_TRACK:this.hls.trigger(n.a.AUDIO_TRACK_LOADED,{details:h,id:o||0,groupId:l||"",stats:e,networkDetails:i,deliveryDirectives:d});break;case L.SUBTITLE_TRACK:this.hls.trigger(n.a.SUBTITLE_TRACK_LOADED,{details:h,id:o||0,groupId:l||"",stats:e,networkDetails:i,deliveryDirectives:d})}}else this.handleManifestParsingError(t,r,"invalid target duration",i)},t}(),w=function(){function t(t){this.hls=void 0,this.loaders={},this.decryptkey=null,this.decrypturl=null,this.hls=t,this._registerListeners()}var e=t.prototype;return e._registerListeners=function(){this.hls.on(n.a.KEY_LOADING,this.onKeyLoading,this)},e._unregisterListeners=function(){this.hls.off(n.a.KEY_LOADING,this.onKeyLoading)},e.destroy=function(){for(var t in this._unregisterListeners(),this.loaders){var e=this.loaders[t];e&&e.destroy()}this.loaders={}},e.onKeyLoading=function(t,e){var r=e.frag,i=r.type,a=this.loaders[i];if(r.decryptdata){var s=r.decryptdata.uri;if(s!==this.decrypturl||null===this.decryptkey){var l=this.hls.config;if(a&&(o.b.warn("abort previous key loader for type:"+i),a.abort()),!s)return void o.b.warn("key uri is falsy");var u=l.loader,h=r.loader=this.loaders[i]=new u(l);this.decrypturl=s,this.decryptkey=null;var d={url:s,frag:r,responseType:"arraybuffer"},c={timeout:l.fragLoadingTimeOut,maxRetry:0,retryDelay:l.fragLoadingRetryDelay,maxRetryDelay:l.fragLoadingMaxRetryTimeout,highWaterMark:0},f={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};h.load(d,c,f)}else this.decryptkey&&(r.decryptdata.key=this.decryptkey,this.hls.trigger(n.a.KEY_LOADED,{frag:r}))}else o.b.warn("Missing decryption data on fragment in onKeyLoading")},e.loadsuccess=function(t,e,r){var i=r.frag;i.decryptdata?(this.decryptkey=i.decryptdata.key=new Uint8Array(t.data),i.loader=null,delete this.loaders[i.type],this.hls.trigger(n.a.KEY_LOADED,{frag:i})):o.b.error("after key load, decryptdata unset")},e.loaderror=function(t,e){var r=e.frag,i=r.loader;i&&i.abort(),delete this.loaders[r.type],this.hls.trigger(n.a.ERROR,{type:s.b.NETWORK_ERROR,details:s.a.KEY_LOAD_ERROR,fatal:!1,frag:r,response:t})},e.loadtimeout=function(t,e){var r=e.frag,i=r.loader;i&&i.abort(),delete this.loaders[r.type],this.hls.trigger(n.a.ERROR,{type:s.b.NETWORK_ERROR,details:s.a.KEY_LOAD_TIMEOUT,fatal:!1,frag:r})},t}();function O(t,e){var r;try{r=new Event("addtrack")}catch(t){(r=document.createEvent("Event")).initEvent("addtrack",!1,!1)}r.track=t,e.dispatchEvent(r)}function x(t,e){var r=t.mode;if("disabled"===r&&(t.mode="hidden"),t.cues&&!t.cues.getCueById(e.id))try{if(t.addCue(e),!t.cues.getCueById(e.id))throw new Error("addCue is failed for: "+e)}catch(r){o.b.debug("[texttrack-utils]: "+r);var i=new self.TextTrackCue(e.startTime,e.endTime,e.text);i.id=e.id,t.addCue(i)}"disabled"===r&&(t.mode=r)}function P(t){var e=t.mode;if("disabled"===e&&(t.mode="hidden"),t.cues){for(var r=t.cues.length;r--;)t.removeCue(t.cues[r]);"disabled"===e&&(t.mode=e)}}function M(t,e,r){var i=t.mode;if("disabled"===i&&(t.mode="hidden"),t.cues&&t.cues.length){for(var a=function(t,e,r){var i=[],a=function(t,e){if(et[r].endTime)return-1;var i=0,a=r;for(;i<=a;){var n=Math.floor((a+i)/2);if(et[n].startTime&&i-1)for(var n=a,s=t.length;n=e&&o.endTime<=r)i.push(o);else if(o.startTime>r)return i}return i}(t.cues,e,r),n=0;n.05&&this.forwardBufferLength>1){var u=Math.min(2,Math.max(1,n)),h=Math.round(2/(1+Math.exp(-.75*o-this.edgeStalled))*20)/20;t.playbackRate=Math.min(u,Math.max(1,h))}else 1!==t.playbackRate&&0!==t.playbackRate&&(t.playbackRate=1)}}}}},a.estimateLiveEdge=function(){var t=this.levelDetails;return null===t?null:t.edge+t.age},a.computeLatency=function(){var t=this.estimateLiveEdge();return null===t?null:t-this.currentTime},e=t,(r=[{key:"latency",get:function(){return this._latency||0}},{key:"maxLatency",get:function(){var t=this.config,e=this.levelDetails;return void 0!==t.liveMaxLatencyDuration?t.liveMaxLatencyDuration:e?t.liveMaxLatencyDurationCount*e.targetduration:0}},{key:"targetLatency",get:function(){var t=this.levelDetails;if(null===t)return null;var e=t.holdBack,r=t.partHoldBack,i=t.targetduration,a=this.config,n=a.liveSyncDuration,s=a.liveSyncDurationCount,o=a.lowLatencyMode,l=this.hls.userConfig,u=o&&r||e;(l.liveSyncDuration||l.liveSyncDurationCount||0===u)&&(u=void 0!==n?n:s*i);var h=i;return u+Math.min(1*this.stallCount,h)}},{key:"liveSyncPosition",get:function(){var t=this.estimateLiveEdge(),e=this.targetLatency,r=this.levelDetails;if(null===t||null===e||null===r)return null;var i=r.edge,a=t-e-this.edgeStalled,n=i-r.totalduration,s=i-(this.config.lowLatencyMode&&r.partTarget||r.targetduration);return Math.min(Math.max(n,a),s)}},{key:"drift",get:function(){var t=this.levelDetails;return null===t?1:t.drift}},{key:"edgeStalled",get:function(){var t=this.levelDetails;if(null===t)return 0;var e=3*(this.config.lowLatencyMode&&t.partTarget||t.targetduration);return Math.max(t.age-e,0)}},{key:"forwardBufferLength",get:function(){var t=this.media,e=this.levelDetails;if(!t||!e)return 0;var r=t.buffered.length;return r?t.buffered.end(r-1):e.edge-this.currentTime}}])&&U(e.prototype,r),i&&U(e,i),t}();function K(t,e){for(var r=0;rt.sn?(n=r-t.start,i=t):(n=t.start-r,i=e),i.duration!==n&&(i.duration=n)}else if(e.sn>t.sn){t.cc===e.cc&&t.minEndPTS?e.start=t.start+(t.minEndPTS-t.start):e.start=t.start+t.duration}else e.start=Math.max(t.start-e.duration,0)}function q(t,e,r,i,n,s){i-r<=0&&(o.b.warn("Fragment should have a positive duration",e),i=r+e.duration,s=n+e.duration);var l=r,u=i,h=e.startPTS,d=e.endPTS;if(Object(a.a)(h)){var c=Math.abs(h-r);Object(a.a)(e.deltaPTS)?e.deltaPTS=Math.max(c,e.deltaPTS):e.deltaPTS=c,l=Math.max(r,h),r=Math.min(r,h),n=Math.min(n,e.startDTS),u=Math.min(i,d),i=Math.max(i,d),s=Math.max(s,e.endDTS)}e.duration=i-r;var f=r-e.start;e.appendedPTS=i,e.start=e.startPTS=r,e.maxStartPTS=l,e.startDTS=n,e.endPTS=i,e.minEndPTS=u,e.endDTS=s;var g,v=e.sn;if(!t||vt.endSN)return 0;var p=v-t.startSN,m=t.fragments;for(m[p]=e,g=p;g>0;g--)Y(m[g],m[g-1]);for(g=p;g=i.length)){var n=i[r].start;if(n){for(var s=e.skippedSegments;se.partTarget&&(l+=1)}if(Object(a.a)(o))return new j(o,Object(a.a)(l)?l:void 0,B.No)}}},e.loadPlaylist=function(t){},e.shouldLoadTrack=function(t){return this.canLoad&&t&&!!t.url&&(!t.details||t.details.live)},e.playlistLoaded=function(t,e,r){var i=this,a=e.details,n=e.stats,s=n.loading.end?Math.max(0,self.performance.now()-n.loading.end):0;if(a.advancedDateTime=Date.now()-s,a.live||null!=r&&r.live){if(a.reloaded(r),r&&this.log("live playlist "+t+" "+(a.advanced?"REFRESHED "+a.lastPartSn+"-"+a.lastPartIndex:"MISSED")),r&&a.fragments.length>0&&X(r,a),!this.canLoad||!a.live)return;var o=void 0,l=void 0;if(a.canBlockReload&&a.endSN&&a.advanced){var u=this.hls.config.lowLatencyMode,h=a.lastPartIndex;u?(o=-1!==h?a.lastPartSn:a.endSN+1,l=-1!==h?h+1:void 0):(o=-1!==h?a.lastPartSn+1:a.endSN+1,l=-1!==h?0:void 0);var d=a.age,c=d+a.ageHeader,f=Math.min(c-a.partTarget,1.5*a.targetduration);if(f>0){if(r&&f>r.tuneInGoal)this.warn("CDN Tune-in goal increased from: "+r.tuneInGoal+" to: "+f+" with playlist age: "+a.age),f=0;else{var g=Math.floor(f/a.targetduration);if(o+=g,void 0!==l)l+=Math.round(f%a.targetduration/a.partTarget);this.log("CDN Tune-in age: "+a.ageHeader+"s last advanced "+d.toFixed(2)+"s goal: "+f+" skip sn "+g+" to part "+l)}a.tuneInGoal=f}var v=this.getDeliveryDirectives(a,e.deliveryDirectives,o,l);return void this.loadPlaylist(v)}var p=function(t,e){var r,i=1e3*t.levelTargetDuration,a=i/2,n=t.age,s=n>0&&n<3*i,o=e.loading.end-e.loading.start,l=t.availabilityDelay;if(!1===t.updated)if(s){var u=333*t.misses;r=Math.max(Math.min(a,2*o),u),t.availabilityDelay=(t.availabilityDelay||0)+r}else r=a;else s?(l=Math.min(l||i/2,n),t.availabilityDelay=l,r=l+i-n):r=i-o;return Math.round(r)}(a,n);this.log("reload live playlist "+t+" in "+Math.round(p)+" ms");var m=this.getDeliveryDirectives(a,e.deliveryDirectives,o,l);this.timer=self.setTimeout((function(){return i.loadPlaylist(m)}),p)}else this.clearTimer()},e.getDeliveryDirectives=function(t,e,r,i){var a=function(t,e){var r=t.canSkipUntil,i=t.canSkipDateRanges,a=t.endSN;return r&&(void 0!==e?e-a:0)-1&&null!==(e=t.context)&&void 0!==e&&e.deliveryDirectives)this.warn("retry playlist loading #"+this.retryCount+' after "'+t.details+'"'),this.loadPlaylist();else{var n=Math.min(Math.pow(2,this.retryCount)*i.levelLoadingRetryDelay,i.levelLoadingMaxRetryTimeout);this.timer=self.setTimeout((function(){return r.loadPlaylist()}),n),this.warn("retry playlist loading #"+this.retryCount+" in "+n+' ms after "'+t.details+'"')}else this.warn('cannot recover from error "'+t.details+'"'),this.clearTimer(),t.fatal=!0;return a},t}();function $(){return($=Object.assign||function(t){for(var e=1;e0){r=a[0].bitrate,a.sort((function(t,e){return t.bitrate-e.bitrate})),this._levels=a;for(var f=0;fthis.hls.config.fragLoadingMaxRetry&&(n=r.frag.level)):n=r.frag.level}break;case s.a.LEVEL_LOAD_ERROR:case s.a.LEVEL_LOAD_TIMEOUT:i&&(i.deliveryDirectives&&(l=!1),n=i.level),o=!0;break;case s.a.REMUX_ALLOC_ERROR:n=r.level,o=!0}void 0!==n&&this.recoverLevel(r,n,o,l)}}},u.recoverLevel=function(t,e,r,i){var a=t.details,n=this._levels[e];if(n.loadError++,r){if(!this.retryLoadingOrFail(t))return void(this.currentLevelIndex=-1);t.levelRetry=!0}if(i){var s=n.url.length;if(s>1&&n.loadError1){var i=(e.urlId+1)%r;this.warn("Switching to redundant URL-id "+i),this._levels.forEach((function(t){t.urlId=i})),this.level=t}},u.onFragLoaded=function(t,e){var r=e.frag;if(void 0!==r&&r.type===A.MAIN){var i=this._levels[r.level];void 0!==i&&(i.fragmentError=0,i.loadError=0)}},u.onLevelLoaded=function(t,e){var r,i,a=e.level,n=e.details,s=this._levels[a];if(!s)return this.warn("Invalid level index "+a),void(null!==(i=e.deliveryDirectives)&&void 0!==i&&i.skip&&(n.deltaUpdateFailed=!0));a===this.currentLevelIndex?(0===s.fragmentError&&(s.loadError=0,this.retryCount=0),this.playlistLoaded(a,e,s.details)):null!==(r=e.deliveryDirectives)&&void 0!==r&&r.skip&&(n.deltaUpdateFailed=!0)},u.onAudioTrackSwitched=function(t,e){var r=this.hls.levels[this.currentLevelIndex];if(r&&r.audioGroupIds){for(var i=-1,a=this.hls.audioTracks[e.id].groupId,n=0;n0){var i=r.urlId,a=r.url[i];if(t)try{a=t.addDirectives(a)}catch(t){this.warn("Could not construct new URL with HLS Delivery Directives: "+t)}this.log("Attempt loading level index "+e+(t?" at sn "+t.msn+" part "+t.part:"")+" with URL-id "+i+" "+a),this.clearTimer(),this.hls.trigger(n.a.LEVEL_LOADING,{url:a,level:e,id:i,deliveryDirectives:t||null})}},u.removeLevel=function(t,e){var r=function(t,r){return r!==e},i=this._levels.filter((function(i,a){return a!==t||i.url.length>1&&void 0!==e&&(i.url=i.url.filter(r),i.audioGroupIds&&(i.audioGroupIds=i.audioGroupIds.filter(r)),i.textGroupIds&&(i.textGroupIds=i.textGroupIds.filter(r)),i.urlId=0,!0)})).map((function(t,e){var r=t.details;return null!=r&&r.fragments&&r.fragments.forEach((function(t){t.level=e})),t}));this._levels=i,this.hls.trigger(n.a.LEVELS_UPDATED,{levels:i})},a=i,(o=[{key:"levels",get:function(){return 0===this._levels.length?null:this._levels}},{key:"level",get:function(){return this.currentLevelIndex},set:function(t){var e,r=this._levels;if(0!==r.length&&(this.currentLevelIndex!==t||null===(e=r[t])||void 0===e||!e.details)){if(t<0||t>=r.length){var i=t<0;if(this.hls.trigger(n.a.ERROR,{type:s.b.OTHER_ERROR,details:s.a.LEVEL_SWITCH_ERROR,level:t,fatal:i,reason:"invalid level idx"}),i)return;t=Math.min(t,r.length-1)}this.clearTimer();var a=this.currentLevelIndex,o=r[a],l=r[t];this.log("switching to level "+t+" from "+a),this.currentLevelIndex=t;var u=$({},l,{level:t,maxBitrate:l.maxBitrate,uri:l.uri,urlId:l.urlId});delete u._urlId,this.hls.trigger(n.a.LEVEL_SWITCHING,u);var h=l.details;if(!h||h.live){var d=this.switchParams(l.uri,null==o?void 0:o.details);this.loadPlaylist(d)}}}},{key:"manualLevel",get:function(){return this.manualLevelIndex},set:function(t){this.manualLevelIndex=t,void 0===this._startLevel&&(this._startLevel=t),-1!==t&&(this.level=t)}},{key:"firstLevel",get:function(){return this._firstLevel},set:function(t){this._firstLevel=t}},{key:"startLevel",get:function(){if(void 0===this._startLevel){var t=this.hls.config.startLevel;return void 0!==t?t:this._firstLevel}return this._startLevel},set:function(t){this._startLevel=t}},{key:"nextLoadLevel",get:function(){return-1!==this.manualLevelIndex?this.manualLevelIndex:this.hls.nextAutoLevel},set:function(t){this.level=t,-1===this.manualLevelIndex&&(this.hls.nextAutoLevel=t)}}])&&J(a.prototype,o),l&&J(a,l),i}(Q);!function(t){t.NOT_LOADED="NOT_LOADED",t.BACKTRACKED="BACKTRACKED",t.APPENDING="APPENDING",t.PARTIAL="PARTIAL",t.OK="OK"}(tt||(tt={}));var it=function(){function t(t){this.activeFragment=null,this.activeParts=null,this.fragments=Object.create(null),this.timeRanges=Object.create(null),this.bufferPadding=.2,this.hls=void 0,this.hls=t,this._registerListeners()}var e=t.prototype;return e._registerListeners=function(){var t=this.hls;t.on(n.a.BUFFER_APPENDED,this.onBufferAppended,this),t.on(n.a.FRAG_BUFFERED,this.onFragBuffered,this),t.on(n.a.FRAG_LOADED,this.onFragLoaded,this)},e._unregisterListeners=function(){var t=this.hls;t.off(n.a.BUFFER_APPENDED,this.onBufferAppended,this),t.off(n.a.FRAG_BUFFERED,this.onFragBuffered,this),t.off(n.a.FRAG_LOADED,this.onFragLoaded,this)},e.destroy=function(){this._unregisterListeners(),this.fragments=this.timeRanges=null},e.getAppendedFrag=function(t,e){if(e===A.MAIN){var r=this.activeFragment,i=this.activeParts;if(!r)return null;if(i)for(var a=i.length;a--;){var n=i[a],s=n?n.end:r.appendedPTS;if(n.start<=t&&void 0!==s&&t<=s)return a>9&&(this.activeParts=i.slice(a-9)),n}else if(r.start<=t&&void 0!==r.appendedPTS&&t<=r.appendedPTS)return r}return this.getBufferedFrag(t,e)},e.getBufferedFrag=function(t,e){for(var r=this.fragments,i=Object.keys(r),a=i.length;a--;){var n=r[i[a]];if((null==n?void 0:n.body.type)===e&&n.buffered){var s=n.body;if(s.start<=t&&t<=s.end)return s}}return null},e.detectEvictedFragments=function(t,e){var r=this;Object.keys(this.fragments).forEach((function(i){var a=r.fragments[i];if(a&&a.buffered){var n=a.range[t];n&&n.time.some((function(t){var i=!r.isTimeBuffered(t.startPTS,t.endPTS,e);return i&&r.removeFragment(a.body),i}))}}))},e.detectPartialFragments=function(t){var e=this,r=this.timeRanges,i=t.frag,a=t.part;if(r&&"initSegment"!==i.sn){var n=nt(i),s=this.fragments[n];s&&(Object.keys(r).forEach((function(t){var n=i.elementaryStreams[t];if(n){var o=r[t],l=null!==a||!0===n.partial;s.range[t]=e.getBufferedTimes(i,a,l,o)}})),s.backtrack=s.loaded=null,Object.keys(s.range).length?s.buffered=!0:this.removeFragment(s.body))}},e.getBufferedTimes=function(t,e,r,i){for(var a={time:[],partial:r},n=e?e.start:t.start,s=e?e.end:t.end,o=t.minEndPTS||s,l=t.maxStartPTS||n,u=0;u=h&&o<=d){a.time.push({startPTS:Math.max(n,i.start(u)),endPTS:Math.min(s,i.end(u))});break}if(nh)a.partial=!0,a.time.push({startPTS:Math.max(n,i.start(u)),endPTS:Math.min(s,i.end(u))});else if(s<=h)break}return a},e.getPartialFragment=function(t){var e,r,i,a=null,n=0,s=this.bufferPadding,o=this.fragments;return Object.keys(o).forEach((function(l){var u=o[l];u&&at(u)&&(r=u.body.start-s,i=u.body.end+s,t>=r&&t<=i&&(e=Math.min(t-r,i-t),n<=e&&(a=u.body,n=e)))})),a},e.getState=function(t){var e=nt(t),r=this.fragments[e];return r?r.buffered?at(r)?tt.PARTIAL:tt.OK:r.backtrack?tt.BACKTRACKED:tt.APPENDING:tt.NOT_LOADED},e.backtrack=function(t,e){var r=nt(t),i=this.fragments[r];if(!i||i.backtrack)return null;var a=i.backtrack=e||i.loaded;return i.loaded=null,a},e.getBacktrackData=function(t){var e=nt(t),r=this.fragments[e];if(r){var i,a=r.backtrack;if(null!=a&&null!==(i=a.payload)&&void 0!==i&&i.byteLength)return a;this.removeFragment(t)}return null},e.isTimeBuffered=function(t,e,r){for(var i,a,n=0;n=i&&e<=a)return!0;if(e<=i)return!1}return!1},e.onFragLoaded=function(t,e){var r=e.frag,i=e.part;if("initSegment"!==r.sn&&!r.bitrateTest&&!i){var a=nt(r);this.fragments[a]={body:r,loaded:e,backtrack:null,buffered:!1,range:Object.create(null)}}},e.onBufferAppended=function(t,e){var r=this,i=e.frag,a=e.part,n=e.timeRanges;if(i.type===A.MAIN)if(this.activeFragment=i,a){var s=this.activeParts;s||(this.activeParts=s=[]),s.push(a)}else this.activeParts=null;this.timeRanges=n,Object.keys(n).forEach((function(t){var e=n[t];if(r.detectEvictedFragments(t,e),!a)for(var s=0;s1&&(this.clearNextTick(),this._tickTimer=self.setTimeout(this._boundTick,0)),this._tickCallCount=0)},e.doTick=function(){},t}(),ot={length:0,start:function(){return 0},end:function(){return 0}},lt=function(){function t(){}return t.isBuffered=function(e,r){try{if(e)for(var i=t.getBuffered(e),a=0;a=i.start(a)&&r<=i.end(a))return!0}catch(t){}return!1},t.bufferInfo=function(e,r,i){try{if(e){var a,n=t.getBuffered(e),s=[];for(a=0;as&&(i[n-1].end=t[a].end):i.push(t[a])}else i.push(t[a])}else i=t;for(var o,l=0,u=e,h=e,d=0;d=c&&er.startCC||t&&t.cc0)r=a+1;else{if(!(s<0))return n;i=a-1}}return null}};function vt(t,e,r){if(null===e||!Array.isArray(t)||!t.length||!Object(a.a)(e))return null;if(e<(t[0].programDateTime||0))return null;if(e>=(t[t.length-1].endProgramDateTime||0))return null;r=r||0;for(var i=0;it&&r.start?-1:0}function yt(t,e,r){var i=1e3*Math.min(e,r.duration+(r.deltaPTS?r.deltaPTS:0));return(r.endProgramDateTime||0)-i>t}function Tt(t){var e="function"==typeof Map?new Map:void 0;return(Tt=function(t){if(null===t||(r=t,-1===Function.toString.call(r).indexOf("[native code]")))return t;var r;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return Et(t,arguments,Lt(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),St(i,t)})(t)}function Et(t,e,r){return(Et=bt()?Reflect.construct:function(t,e,r){var i=[null];i.push.apply(i,e);var a=new(Function.bind.apply(t,i));return r&&St(a,r.prototype),a}).apply(null,arguments)}function bt(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function St(t,e){return(St=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function Lt(t){return(Lt=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}var At=Math.pow(2,17),Rt=function(){function t(t){this.config=void 0,this.loader=null,this.partLoadTimeout=-1,this.config=t}var e=t.prototype;return e.destroy=function(){this.loader&&(this.loader.destroy(),this.loader=null)},e.abort=function(){this.loader&&this.loader.abort()},e.load=function(t,e){var r=this,i=t.url;if(!i)return Promise.reject(new kt({type:s.b.NETWORK_ERROR,details:s.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,networkDetails:null},"Fragment does not have a "+(i?"part list":"url")));this.abort();var a=this.config,n=a.fLoader,o=a.loader;return new Promise((function(i,l){r.loader&&r.loader.destroy();var u=r.loader=t.loader=n?new n(a):new o(a),h=Dt(t),d={timeout:a.fragLoadingTimeOut,maxRetry:0,retryDelay:0,maxRetryDelay:a.fragLoadingMaxRetryTimeout,highWaterMark:At};t.stats=u.stats,u.load(h,d,{onSuccess:function(e,a,n,s){r.resetLoader(t,u),i({frag:t,part:null,payload:e.data,networkDetails:s})},onError:function(e,i,a){r.resetLoader(t,u),l(new kt({type:s.b.NETWORK_ERROR,details:s.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,response:e,networkDetails:a}))},onAbort:function(e,i,a){r.resetLoader(t,u),l(new kt({type:s.b.NETWORK_ERROR,details:s.a.INTERNAL_ABORTED,fatal:!1,frag:t,networkDetails:a}))},onTimeout:function(e,i,a){r.resetLoader(t,u),l(new kt({type:s.b.NETWORK_ERROR,details:s.a.FRAG_LOAD_TIMEOUT,fatal:!1,frag:t,networkDetails:a}))},onProgress:function(r,i,a,n){e&&e({frag:t,part:null,payload:a,networkDetails:n})}})}))},e.loadPart=function(t,e,r){var i=this;this.abort();var a=this.config,n=a.fLoader,o=a.loader;return new Promise((function(l,u){i.loader&&i.loader.destroy();var h=i.loader=t.loader=n?new n(a):new o(a),d=Dt(t,e),c={timeout:a.fragLoadingTimeOut,maxRetry:0,retryDelay:0,maxRetryDelay:a.fragLoadingMaxRetryTimeout,highWaterMark:At};e.stats=h.stats,h.load(d,c,{onSuccess:function(a,n,s,o){i.resetLoader(t,h),i.updateStatsFromPart(t,e);var u={frag:t,part:e,payload:a.data,networkDetails:o};r(u),l(u)},onError:function(r,a,n){i.resetLoader(t,h),u(new kt({type:s.b.NETWORK_ERROR,details:s.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,part:e,response:r,networkDetails:n}))},onAbort:function(r,a,n){t.stats.aborted=e.stats.aborted,i.resetLoader(t,h),u(new kt({type:s.b.NETWORK_ERROR,details:s.a.INTERNAL_ABORTED,fatal:!1,frag:t,part:e,networkDetails:n}))},onTimeout:function(r,a,n){i.resetLoader(t,h),u(new kt({type:s.b.NETWORK_ERROR,details:s.a.FRAG_LOAD_TIMEOUT,fatal:!1,frag:t,part:e,networkDetails:n}))}})}))},e.updateStatsFromPart=function(t,e){var r=t.stats,i=e.stats,a=i.total;if(r.loaded+=i.loaded,a){var n=Math.round(t.duration/e.duration),s=Math.min(Math.round(r.loaded/a),n),o=(n-s)*Math.round(r.loaded/s);r.total=r.loaded+o}else r.total=Math.max(r.loaded,r.total);var l=r.loading,u=i.loading;l.start?l.first+=u.first-u.start:(l.start=u.start,l.first=u.first),l.end=u.end},e.resetLoader=function(t,e){t.loader=null,this.loader===e&&(self.clearTimeout(this.partLoadTimeout),this.loader=null),e.destroy()},t}();function Dt(t,e){void 0===e&&(e=null);var r=e||t,i={frag:t,part:e,responseType:"arraybuffer",url:r.url,rangeStart:0,rangeEnd:0},n=r.byteRangeStartOffset,s=r.byteRangeEndOffset;return Object(a.a)(n)&&Object(a.a)(s)&&(i.rangeStart=n,i.rangeEnd=s),i}var kt=function(t){var e,r;function i(e){for(var r,i=arguments.length,a=new Array(i>1?i-1:0),n=1;nh)&&(e.loader&&(this.log("seeking outside of buffer while fragment load in progress, cancel fragment load"),e.loader.abort()),this.resetLoadingState())}r&&(this.lastCurrentTime=s),this.loadedmetadata||o.len||(this.nextLoadPosition=this.startPosition=s),this.tick()},c.onMediaEnded=function(){this.startPosition=this.lastCurrentTime=0},c.onKeyLoaded=function(t,e){if(this.state===Pt&&this.levels){this.state=xt;var r=this.levels[e.frag.level].details;r&&this.loadFragment(e.frag,r,e.frag.start)}},c.onHandlerDestroying=function(){this.stopLoad(),t.prototype.onHandlerDestroying.call(this)},c.onHandlerDestroyed=function(){this.state=Ot,this.hls.off(n.a.KEY_LOADED,this.onKeyLoaded,this),this.fragmentLoader&&this.fragmentLoader.destroy(),this.decrypter&&this.decrypter.destroy(),this.hls=this.log=this.warn=this.decrypter=this.fragmentLoader=this.fragmentTracker=null,t.prototype.onHandlerDestroyed.call(this)},c.loadFragment=function(t,e,r){this._loadFragForPlayback(t,e,r)},c._loadFragForPlayback=function(t,e,r){var i=this;this._doFragLoad(t,e,r,(function(e){if(i.fragContextChanged(t))return i.warn("Fragment "+t.sn+(e.part?" p: "+e.part.index:"")+" of level "+t.level+" was dropped during download."),void i.fragmentTracker.removeFragment(t);t.stats.chunkCount++,i._handleFragmentLoadProgress(e)})).then((function(e){if(e){i.fragLoadError=0;var r=i.state;if(!i.fragContextChanged(t))return"payload"in e&&(i.log("Loaded fragment "+t.sn+" of level "+t.level),i.hls.trigger(n.a.FRAG_LOADED,e),i.state===Gt)?(i.fragmentTracker.backtrack(t,e),void i.resetFragmentLoading(t)):void i._handleFragmentLoadComplete(e);(r===Mt||r===Gt||!i.fragCurrent&&r===Ut)&&(i.fragmentTracker.removeFragment(t),i.state=xt)}})).catch((function(e){i.warn(e),i.resetFragmentLoading(t)}))},c.flushMainBuffer=function(t,e,r){void 0===r&&(r=null);var i={startOffset:t,endOffset:e,type:r};this.fragLoadError=0,this.hls.trigger(n.a.BUFFER_FLUSHING,i)},c._loadInitSegment=function(t){var e=this;this._doFragLoad(t).then((function(r){if(!r||e.fragContextChanged(t)||!e.levels)throw new Error("init load aborted");return r})).then((function(r){var i=e.hls,a=r.payload,s=t.decryptdata;if(a&&a.byteLength>0&&s&&s.key&&s.iv&&"AES-128"===s.method){var o=self.performance.now();return e.decrypter.webCryptoDecrypt(new Uint8Array(a),s.key.buffer,s.iv.buffer).then((function(e){var a=self.performance.now();return i.trigger(n.a.FRAG_DECRYPTED,{frag:t,payload:e,stats:{tstart:o,tdecrypt:a}}),r.payload=e,r}))}return r})).then((function(r){var i=e.fragCurrent,a=e.hls,s=e.levels;if(!s)throw new Error("init load aborted, missing levels");var o=s[t.level].details.initSegment,l=t.stats;e.state=xt,e.fragLoadError=0,o.data=new Uint8Array(r.payload),l.parsing.start=l.buffering.start=self.performance.now(),l.parsing.end=l.buffering.end=self.performance.now(),r.frag===i&&a.trigger(n.a.FRAG_BUFFERED,{stats:l,frag:i,part:null,id:t.type}),e.tick()})).catch((function(r){e.warn(r),e.resetFragmentLoading(t)}))},c.fragContextChanged=function(t){var e=this.fragCurrent;return!t||!e||t.level!==e.level||t.sn!==e.sn||t.urlId!==e.urlId},c.fragBufferedComplete=function(t,e){var r=this.mediaBuffer?this.mediaBuffer:this.media;this.log("Buffered "+t.type+" sn: "+t.sn+(e?" part: "+e.index:"")+" of "+("[stream-controller]"===this.logPrefix?"level":"track")+" "+t.level+" "+It.toString(lt.getBuffered(r))),this.state=xt,this.tick()},c._handleFragmentLoadComplete=function(t){var e=this.transmuxer;if(e){var r=t.frag,i=t.part,a=t.partsLoaded,n=!a||0===a.length||a.some((function(t){return!t})),s=new ut(r.level,r.sn,r.stats.chunkCount+1,0,i?i.index:-1,!n);e.flush(s)}},c._handleFragmentLoadProgress=function(t){},c._doFragLoad=function(t,e,r,i){var s=this;if(void 0===r&&(r=null),!this.levels)throw new Error("frag load aborted, missing levels");if(r=Math.max(t.start,r||0),this.config.lowLatencyMode&&e){var o=e.partList;if(o&&i){r>t.end&&e.fragmentHint&&(t=e.fragmentHint);var l=this.getNextPart(o,t,r);if(l>-1){var u=o[l];return this.log("Loading part sn: "+t.sn+" p: "+u.index+" cc: "+t.cc+" of playlist ["+e.startSN+"-"+e.endSN+"] parts [0-"+l+"-"+(o.length-1)+"] "+("[stream-controller]"===this.logPrefix?"level":"track")+": "+t.level+", target: "+parseFloat(r.toFixed(3))),this.nextLoadPosition=u.start+u.duration,this.state=Mt,this.hls.trigger(n.a.FRAG_LOADING,{frag:t,part:o[l],targetBufferTime:r}),this.doFragPartsLoad(t,o,l,i).catch((function(t){return s.handleFragLoadError(t)}))}if(!t.url||this.loadedEndOfParts(o,r))return Promise.resolve(null)}}return this.log("Loading fragment "+t.sn+" cc: "+t.cc+" "+(e?"of ["+e.startSN+"-"+e.endSN+"] ":"")+("[stream-controller]"===this.logPrefix?"level":"track")+": "+t.level+", target: "+parseFloat(r.toFixed(3))),Object(a.a)(t.sn)&&!this.bitrateTest&&(this.nextLoadPosition=t.start+t.duration),this.state=Mt,this.hls.trigger(n.a.FRAG_LOADING,{frag:t,targetBufferTime:r}),this.fragmentLoader.load(t,i).catch((function(t){return s.handleFragLoadError(t)}))},c.doFragPartsLoad=function(t,e,r,i){var a=this;return new Promise((function(s,o){var l=[];!function r(u){var h=e[u];a.fragmentLoader.loadPart(t,h,i).then((function(i){l[h.index]=i;var o=i.part;a.hls.trigger(n.a.FRAG_LOADED,i);var d=e[u+1];if(!d||d.fragment!==t)return s({frag:t,part:o,partsLoaded:l});r(u+1)})).catch(o)}(r)}))},c.handleFragLoadError=function(t){var e=t.data;return e&&e.details===s.a.INTERNAL_ABORTED?this.handleFragLoadAborted(e.frag,e.part):this.hls.trigger(n.a.ERROR,e),null},c._handleTransmuxerFlush=function(t){var e=this.getCurrentContext(t);if(e&&this.state===Ut){var r=e.frag,i=e.part,a=e.level,n=self.performance.now();r.stats.parsing.end=n,i&&(i.stats.parsing.end=n),this.updateLevelTiming(r,i,a,t.partial)}else this.fragCurrent||(this.state=xt)},c.getCurrentContext=function(t){var e=this.levels,r=t.level,i=t.sn,a=t.part;if(!e||!e[r])return this.warn("Levels object was unset while buffering fragment "+i+" of level "+r+". The current chunk will not be buffered."),null;var n=e[r],s=a>-1?function(t,e,r){if(!t||!t.details)return null;var i=t.details.partList;if(i)for(var a=i.length;a--;){var n=i[a];if(n.index===r&&n.fragment.sn===e)return n}return null}(n,i,a):null,o=s?s.fragment:function(t,e){if(!t||!t.details)return null;var r=t.details,i=r.fragments[e-r.startSN];return i||((i=r.fragmentHint)&&i.sn===e?i:null)}(n,i);return o?{frag:o,part:s,level:n}:null},c.bufferFragmentData=function(t,e,r,i){if(t&&this.state===Ut){var a=t.data1,s=t.data2,o=a;if(a&&s&&(o=Object(l.a)(a,s)),o&&o.length){var u={type:t.type,frag:e,part:r,chunkMeta:i,parent:e.type,data:o};this.hls.trigger(n.a.BUFFER_APPENDING,u),t.dropped&&t.independent&&!r&&this.flushBufferGap(e)}}},c.flushBufferGap=function(t){var e=this.media;if(e)if(lt.isBuffered(e,e.currentTime)){var r=e.currentTime,i=lt.bufferInfo(e,r,0),a=t.duration,n=Math.min(2*this.config.maxFragLookUpTolerance,.25*a),s=Math.max(Math.min(t.start-n,i.end-n),r+n);t.start-s>n&&this.flushMainBuffer(s,t.start)}else this.flushMainBuffer(0,t.start)},c.reduceMaxBufferLength=function(t){var e=this.config,r=t||e.maxBufferLength;return e.maxMaxBufferLength>=r&&(e.maxMaxBufferLength/=2,this.warn("Reduce max buffer length to "+e.maxMaxBufferLength+"s"),!0)},c.getNextFragment=function(t,e){var r=e.fragments,i=r.length;if(!i)return null;var a,n=this.config,s=r[0].start;if(!e.initSegment||e.initSegment.data||this.bitrateTest)if(e.live){var o=n.initialLiveManifestSize;if(i-1&&rr.start&&r.loaded},c.getInitialLiveFragment=function(t,e){var r=this.fragPrevious,i=null;if(r){if(t.hasProgramDateTime&&(this.log("Live playlist, switching playlist, load frag with same PDT: "+r.programDateTime),i=vt(e,r.endProgramDateTime,this.config.maxFragLookUpTolerance)),!i){var a=r.sn+1;if(a>=t.startSN&&a<=t.endSN){var n=e[a-t.startSN];r.cc===n.cc&&(i=n,this.log("Live playlist, switching playlist, load frag with next SN: "+i.sn))}i||(i=function(t,e){return gt.search(t,(function(t){return t.cce?-1:0}))}(e,r.cc))&&this.log("Live playlist, switching playlist, load frag with same CC: "+i.sn)}}else{var s=this.hls.liveSyncPosition;null!==s&&(i=this.getFragmentAtPosition(s,this.bitrateTest?t.fragmentEnd:t.edge,t))}return i},c.getFragmentAtPosition=function(t,e,r){var i,a=this.config,n=this.fragPrevious,s=r.fragments,o=r.endSN,l=r.fragmentHint,u=a.maxFragLookUpTolerance,h=!!(a.lowLatencyMode&&r.partList&&l);(h&&l&&!this.bitrateTest&&(s=s.concat(l),o=l.sn),te-u?0:u):i=s[s.length-1];if(i){var d=i.sn-r.startSN,c=n&&i.level===n.level,f=s[d+1];if(this.fragmentTracker.getState(i)===tt.BACKTRACKED){i=null;for(var g=d;s[g]&&this.fragmentTracker.getState(s[g])===tt.BACKTRACKED;)i=n?s[g--]:s[--g];i||(i=f)}else n&&i.sn===n.sn&&!h&&c&&(i.sn=n-e.maxFragLookUpTolerance&&a<=s;if(null!==i&&r.duration>i&&(a0?(s=t.fragments[0].start,t.alignedSliding&&Object(a.a)(s)?this.log("Live playlist sliding:"+s.toFixed(3)):s||(this.warn("["+this.constructor.name+"] Live playlist - outdated PTS, unknown sliding"),ct(this.fragPrevious,n,t))):(this.log("Live playlist - first load, unknown sliding"),ct(this.fragPrevious,n,t)),s},c.waitForCdnTuneIn=function(t){return t.live&&t.canBlockReload&&t.tuneInGoal>Math.max(t.partHoldBack,3*t.partTarget)},c.setStartPosition=function(t,e){var r=this.startPosition;if(-1===this.startPosition||-1===this.lastCurrentTime){var i=t.startTimeOffset;Object(a.a)(i)?(i<0&&(this.log("Negative start time offset "+i+", count from end of last fragment"),i=e+t.totalduration+i),this.log("Start time offset found in playlist, adjust startPosition to "+i),this.startPosition=r=i):t.live?r=this.hls.liveSyncPosition||e:this.startPosition=r=0,this.lastCurrentTime=r}this.nextLoadPosition=r},c.getLoadPosition=function(){var t=this.media,e=0;return this.loadedmetadata?e=t.currentTime:this.nextLoadPosition&&(e=this.nextLoadPosition),e},c.handleFragLoadAborted=function(t,e){this.transmuxer&&"initSegment"!==t.sn&&(this.warn("Fragment "+t.sn+(e?" part"+e.index:"")+" of level "+t.level+" was aborted"),this.resetFragmentLoading(t))},c.resetFragmentLoading=function(t){this.fragCurrent&&this.fragContextChanged(t)||(this.state=xt)},c.onFragmentOrKeyLoadError=function(t,e){if(!e.fatal){var r=e.frag;if(r&&r.type===t){this.fragCurrent;var i=this.config;if(this.fragLoadError+1<=i.fragLoadingMaxRetry){if(this.resetLiveStartWhenNotLoaded(r.level))return;var a=Math.min(Math.pow(2,this.fragLoadError)*i.fragLoadingRetryDelay,i.fragLoadingMaxRetryTimeout);this.warn("Fragment "+r.sn+" of "+t+" "+r.level+" failed to load, retrying in "+a+"ms"),this.retryDate=self.performance.now()+a,this.fragLoadError++,this.state=Ft}else e.levelRetry?(t===A.AUDIO&&(this.fragCurrent=null),this.fragLoadError=0,this.state=xt):(o.b.error(e.details+" reaches max retry, redispatch as fatal ..."),e.fatal=!0,this.hls.stopLoad(),this.state=jt)}}},c.afterBufferFlushed=function(t,e){if(t){var r=lt.getBuffered(t);this.fragmentTracker.detectEvictedFragments(e,r),this.state===Kt&&this.resetLoadingState()}},c.resetLoadingState=function(){this.fragCurrent=null,this.fragPrevious=null,this.state=xt},c.resetLiveStartWhenNotLoaded=function(t){if(!this.loadedmetadata){this.startFragRequested=!1;var e=this.levels?this.levels[t].details:null;if(null!=e&&e.live)return this.startPosition=-1,this.setStartPosition(e,0),this.resetLoadingState(),!0;this.nextLoadPosition=this.startPosition}return!1},c.updateLevelTiming=function(t,e,r,i){var a=this,s=r.details;Object.keys(t.elementaryStreams).reduce((function(e,o){var l=t.elementaryStreams[o];if(l){var u=l.endPTS-l.startPTS;if(u<=0)return a.warn("Could not parse fragment "+t.sn+" "+o+" duration reliably ("+u+") resetting transmuxer to fallback to playlist timing"),a.resetTransmuxer(),e||!1;var h=i?0:q(s,t,l.startPTS,l.endPTS,l.startDTS,l.endDTS);return a.hls.trigger(n.a.LEVEL_PTS_UPDATED,{details:s,level:r,drift:h,type:o,frag:t,start:l.startPTS,end:l.endPTS}),!0}return e}),!1)?(this.state=Bt,this.hls.trigger(n.a.FRAG_PARSED,{frag:t,part:e})):this.resetLoadingState()},c.resetTransmuxer=function(){this.transmuxer&&(this.transmuxer.destroy(),this.transmuxer=null)},u=i,(h=[{key:"state",get:function(){return this._state},set:function(t){var e=this._state;e!==t&&(this._state=t,this.log(e+"->"+t))}}])&&Ct(u.prototype,h),d&&Ct(u,d),i}(st);function Yt(){return self.MediaSource||self.WebKitMediaSource}function qt(){return self.SourceBuffer||self.WebKitSourceBuffer}var Xt=r(17),zt=r(9),Qt=r(13),$t=Yt()||{isTypeSupported:function(){return!1}},Jt=function(){function t(t,e,r,i){var a=this;this.hls=void 0,this.id=void 0,this.observer=void 0,this.frag=null,this.part=null,this.worker=void 0,this.onwmsg=void 0,this.transmuxer=null,this.onTransmuxComplete=void 0,this.onFlush=void 0,this.hls=t,this.id=e,this.onTransmuxComplete=r,this.onFlush=i;var l=t.config,u=function(e,r){(r=r||{}).frag=a.frag,r.id=a.id,t.trigger(e,r)};this.observer=new Qt.EventEmitter,this.observer.on(n.a.FRAG_DECRYPTED,u),this.observer.on(n.a.ERROR,u);var h={mp4:$t.isTypeSupported("video/mp4"),mpeg:$t.isTypeSupported("audio/mpeg"),mp3:$t.isTypeSupported('audio/mp4; codecs="mp3"')},d=navigator.vendor;if(l.enableWorker&&"undefined"!=typeof Worker){var c;o.b.log("demuxing in webworker");try{c=this.worker=Xt(18),this.onwmsg=this.onWorkerMessage.bind(this),c.addEventListener("message",this.onwmsg),c.onerror=function(e){t.trigger(n.a.ERROR,{type:s.b.OTHER_ERROR,details:s.a.INTERNAL_EXCEPTION,fatal:!0,event:"demuxerWorker",error:new Error(e.message+" ("+e.filename+":"+e.lineno+")")})},c.postMessage({cmd:"init",typeSupported:h,vendor:d,id:e,config:JSON.stringify(l)})}catch(t){o.b.warn("Error in worker:",t),o.b.error("Error while initializing DemuxerWorker, fallback to inline"),c&&self.URL.revokeObjectURL(c.objectURL),this.transmuxer=new zt.c(this.observer,h,l,d),this.worker=null}}else this.transmuxer=new zt.c(this.observer,h,l,d)}var e=t.prototype;return e.destroy=function(){var t=this.worker;if(t)t.removeEventListener("message",this.onwmsg),t.terminate(),this.worker=null;else{var e=this.transmuxer;e&&(e.destroy(),this.transmuxer=null)}var r=this.observer;r&&r.removeAllListeners(),this.observer=null},e.push=function(t,e,r,i,a,n,s,l,u,h){var d=this;u.transmuxing.start=self.performance.now();var c=this.transmuxer,f=this.worker,g=n?n.start:a.start,v=a.decryptdata,p=this.frag,m=!(p&&a.cc===p.cc),y=!(p&&u.level===p.level),T=p?u.sn-p.sn:-1,E=this.part?u.part-this.part.index:1,b=!y&&(1===T||0===T&&1===E),S=self.performance.now();(y||T||0===a.stats.parsing.start)&&(a.stats.parsing.start=S),!n||!E&&b||(n.stats.parsing.start=S);var L=new zt.b(m,b,l,y,g);if(!b||m){o.b.log("[transmuxer-interface, "+a.type+"]: Starting new transmux session for sn: "+u.sn+" p: "+u.part+" level: "+u.level+" id: "+u.id+"\n discontinuity: "+m+"\n trackSwitch: "+y+"\n contiguous: "+b+"\n accurateTimeOffset: "+l+"\n timeOffset: "+g);var A=new zt.a(r,i,e,s,h);this.configureTransmuxer(A)}if(this.frag=a,this.part=n,f)f.postMessage({cmd:"demux",data:t,decryptdata:v,chunkMeta:u,state:L},t instanceof ArrayBuffer?[t]:[]);else if(c){var R=c.push(t,v,u,L);Object(zt.d)(R)?R.then((function(t){d.handleTransmuxComplete(t)})):this.handleTransmuxComplete(R)}},e.flush=function(t){var e=this;t.transmuxing.start=self.performance.now();var r=this.transmuxer,i=this.worker;if(i)i.postMessage({cmd:"flush",chunkMeta:t});else if(r){var a=r.flush(t);Object(zt.d)(a)?a.then((function(r){e.handleFlushResult(r,t)})):this.handleFlushResult(a,t)}},e.handleFlushResult=function(t,e){var r=this;t.forEach((function(t){r.handleTransmuxComplete(t)})),this.onFlush(e)},e.onWorkerMessage=function(t){var e=t.data,r=this.hls;switch(e.event){case"init":self.URL.revokeObjectURL(this.worker.objectURL);break;case"transmuxComplete":this.handleTransmuxComplete(e.data);break;case"flush":this.onFlush(e.data);break;default:e.data=e.data||{},e.data.frag=this.frag,e.data.id=this.id,r.trigger(e.event,e.data)}},e.configureTransmuxer=function(t){var e=this.worker,r=this.transmuxer;e?e.postMessage({cmd:"configure",config:t}):r&&r.configure(t)},e.handleTransmuxComplete=function(t){t.chunkMeta.transmuxing.end=self.performance.now(),this.onTransmuxComplete(t)},t}(),Zt=function(){function t(t,e,r,i){this.config=void 0,this.media=void 0,this.fragmentTracker=void 0,this.hls=void 0,this.nudgeRetry=0,this.stallReported=!1,this.stalled=null,this.moved=!1,this.seeking=!1,this.config=t,this.media=e,this.fragmentTracker=r,this.hls=i}var e=t.prototype;return e.destroy=function(){this.hls=this.fragmentTracker=this.media=null},e.poll=function(t){var e=this.config,r=this.media,i=this.stalled,a=r.currentTime,n=r.seeking,s=this.seeking&&!n,l=!this.seeking&&n;if(this.seeking=n,a===t){if((l||s)&&(this.stalled=null),!r.paused&&!r.ended&&0!==r.playbackRate&<.getBuffered(r).length){var u=lt.bufferInfo(r,a,0),h=u.len>0,d=u.nextStart||0;if(h||d){if(n){var c=u.len>2,f=!d||d-a>2&&!this.fragmentTracker.getPartialFragment(a);if(c||f)return;this.moved=!1}if(!this.moved&&null!==this.stalled){var g,v=Math.max(d,u.start||0)-a,p=this.hls.levels?this.hls.levels[this.hls.currentLevel]:null,m=(null==p||null===(g=p.details)||void 0===g?void 0:g.live)?2*p.details.targetduration:2;if(v>0&&v<=m)return void this._trySkipBufferHole(null)}var y=self.performance.now();if(null!==i){var T=y-i;!n&&T>=250&&this._reportStall(u.len);var E=lt.bufferInfo(r,a,e.maxBufferHole);this._tryFixBufferStall(E,T)}else this.stalled=y}}}else if(this.moved=!0,null!==i){if(this.stallReported){var b=self.performance.now()-i;o.b.warn("playback not stuck anymore @"+a+", after "+Math.round(b)+"ms"),this.stallReported=!1}this.stalled=null,this.nudgeRetry=0}},e._tryFixBufferStall=function(t,e){var r=this.config,i=this.fragmentTracker,a=this.media.currentTime,n=i.getPartialFragment(a);if(n&&this._trySkipBufferHole(n))return;t.len>r.maxBufferHole&&e>1e3*r.highBufferWatchdogPeriod&&(o.b.warn("Trying to nudge playhead over buffer-hole"),this.stalled=null,this._tryNudgeBuffer())},e._reportStall=function(t){var e=this.hls,r=this.media;this.stallReported||(this.stallReported=!0,o.b.warn("Playback stalling at @"+r.currentTime+" due to low buffer (buffer="+t+")"),e.trigger(n.a.ERROR,{type:s.b.MEDIA_ERROR,details:s.a.BUFFER_STALLED_ERROR,fatal:!1,buffer:t}))},e._trySkipBufferHole=function(t){for(var e=this.config,r=this.hls,i=this.media,a=i.currentTime,l=0,u=lt.getBuffered(i),h=0;h=l&&a0&&-1===t&&(this.log("Override startPosition with lastCurrentTime @"+e.toFixed(3)),t=e),this.state=xt,this.nextLoadPosition=this.startPosition=this.lastCurrentTime=t,this.tick()}else this._forceStartLoad=!0,this.state=Ot},c.stopLoad=function(){this._forceStartLoad=!1,t.prototype.stopLoad.call(this)},c.doTick=function(){switch(this.state){case xt:this.doTickIdle();break;case Vt:var t,e=this.levels,r=this.level,i=null==e||null===(t=e[r])||void 0===t?void 0:t.details;if(i&&(!i.live||this.levelLastLoaded===this.level)){if(this.waitForCdnTuneIn(i))break;this.state=xt;break}break;case Ft:var a,n=self.performance.now(),s=this.retryDate;(!s||n>=s||null!==(a=this.media)&&void 0!==a&&a.seeking)&&(this.log("retryDate reached, switch back to IDLE state"),this.state=xt)}this.onTickEnd()},c.onTickEnd=function(){t.prototype.onTickEnd.call(this),this.checkBuffer(),this.checkFragmentChanged()},c.doTickIdle=function(){var t,e,r=this.hls,i=this.levelLastLoaded,s=this.levels,o=this.media,l=r.config,u=r.nextLoadLevel;if(null!==i&&(o||!this.startFragRequested&&l.startFragPrefetch)&&(!this.altAudio||!this.audioOnly)&&s&&s[u]){var h=s[u];this.level=r.nextLoadLevel=u;var d=h.details;if(!d||this.state===Vt||d.live&&this.levelLastLoaded!==u)this.state=Vt;else{var c=this.getLoadPosition();if(Object(a.a)(c)){var f=d.initSegment,g=0;if(!f||f.data||this.bitrateTest){var v,p=h.maxBitrate;v=p?Math.max(8*l.maxBufferSize/p,l.maxBufferLength):l.maxBufferLength,v=Math.min(v,l.maxMaxBufferLength);var m=c=v)return;if(this._streamEnded(y,d)){var T={};return this.altAudio&&(T.type="video"),this.hls.trigger(n.a.BUFFER_EOS,T),void(this.state=Kt)}if(g=y.end,(f=this.getNextFragment(g,d))&&this.fragmentTracker.getState(f)===tt.OK&&this.nextLoadPosition>g&&(f=this.getNextFragment(this.nextLoadPosition,d)),!f)return}"identity"!==(null===(t=f.decryptdata)||void 0===t?void 0:t.keyFormat)||null!==(e=f.decryptdata)&&void 0!==e&&e.key?this.loadFragment(f,d,g):(this.log("Loading key for "+f.sn+" of ["+d.startSN+"-"+d.endSN+"], level "+u),this.loadKey(f))}}}},c.loadKey=function(t){this.state=Pt,this.hls.trigger(n.a.KEY_LOADING,{frag:t})},c.loadFragment=function(e,r,i){var a,n=this.fragmentTracker.getState(e);if(this.fragCurrent=e,n===tt.BACKTRACKED){var s=this.fragmentTracker.getBacktrackData(e);if(s)return this._handleFragmentLoadProgress(s),void this._handleFragmentLoadComplete(s);n=tt.NOT_LOADED}n===tt.NOT_LOADED||n===tt.PARTIAL?"initSegment"===e.sn?this._loadInitSegment(e):this.bitrateTest?(e.bitrateTest=!0,this.log("Fragment "+e.sn+" of level "+e.level+" is being downloaded to test bitrate and will not be buffered"),this._loadBitrateTestFrag(e)):(this.startFragRequested=!0,t.prototype.loadFragment.call(this,e,r,i)):n===tt.APPENDING?this.reduceMaxBufferLength(e.duration)&&this.fragmentTracker.removeFragment(e):0===(null===(a=this.media)||void 0===a?void 0:a.buffered.length)&&this.fragmentTracker.removeAllFragments()},c.getAppendedFrag=function(t){var e=this.fragmentTracker.getAppendedFrag(t,A.MAIN);return e&&"fragment"in e?e.fragment:e},c.getBufferedFrag=function(t){return this.fragmentTracker.getBufferedFrag(t,A.MAIN)},c.followingBufferedFrag=function(t){return t?this.getBufferedFrag(t.end+.5):null},c.immediateLevelSwitch=function(){this.abortCurrentFrag(),this.flushMainBuffer(0,Number.POSITIVE_INFINITY)},c.nextLevelSwitch=function(){var t=this.levels,e=this.media;if(null!=e&&e.readyState){var r,i=this.getAppendedFrag(e.currentTime);if(i&&i.start>1&&this.flushMainBuffer(0,i.start-1),!e.paused&&t){var a=t[this.hls.nextLoadLevel],n=this.fragLastKbps;r=n&&this.fragCurrent?this.fragCurrent.duration*a.maxBitrate/(1e3*n)+1:0}else r=0;var s=this.getBufferedFrag(e.currentTime+r);if(s){var o=this.followingBufferedFrag(s);if(o){this.abortCurrentFrag();var l=o.maxStartPTS?o.maxStartPTS:o.start,u=o.duration,h=Math.max(s.end,l+Math.min(Math.max(u-this.config.maxFragLookUpTolerance,.5*u),.75*u));this.flushMainBuffer(h,Number.POSITIVE_INFINITY)}}}},c.abortCurrentFrag=function(){var t=this.fragCurrent;this.fragCurrent=null,null!=t&&t.loader&&t.loader.abort(),this.nextLoadPosition=this.getLoadPosition()},c.flushMainBuffer=function(e,r){t.prototype.flushMainBuffer.call(this,e,r,this.altAudio?"video":null)},c.onMediaAttached=function(e,r){t.prototype.onMediaAttached.call(this,e,r);var i=r.media;this.onvplaying=this.onMediaPlaying.bind(this),this.onvseeked=this.onMediaSeeked.bind(this),i.addEventListener("playing",this.onvplaying),i.addEventListener("seeked",this.onvseeked),this.gapController=new Zt(this.config,i,this.fragmentTracker,this.hls)},c.onMediaDetaching=function(){var e=this.media;e&&(e.removeEventListener("playing",this.onvplaying),e.removeEventListener("seeked",this.onvseeked),this.onvplaying=this.onvseeked=null,this.videoBuffer=null),this.fragPlaying=null,this.gapController&&(this.gapController.destroy(),this.gapController=null),t.prototype.onMediaDetaching.call(this)},c.onMediaPlaying=function(){this.tick()},c.onMediaSeeked=function(){var t=this.media,e=t?t.currentTime:null;Object(a.a)(e)&&this.log("Media seeked to "+e.toFixed(3)),this.tick()},c.onManifestLoading=function(){this.log("Trigger BUFFER_RESET"),this.hls.trigger(n.a.BUFFER_RESET,void 0),this.fragmentTracker.removeAllFragments(),this.stalled=!1,this.startPosition=this.lastCurrentTime=0,this.fragPlaying=null},c.onManifestParsed=function(t,e){var r,i,a,n=!1,s=!1;e.levels.forEach((function(t){(r=t.audioCodec)&&(-1!==r.indexOf("mp4a.40.2")&&(n=!0),-1!==r.indexOf("mp4a.40.5")&&(s=!0))})),this.audioCodecSwitch=n&&s&&!("function"==typeof(null==(a=qt())||null===(i=a.prototype)||void 0===i?void 0:i.changeType)),this.audioCodecSwitch&&this.log("Both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC"),this.levels=e.levels,this.startFragRequested=!1},c.onLevelLoading=function(t,e){var r=this.levels;if(r&&this.state===xt){var i=r[e.level];(!i.details||i.details.live&&this.levelLastLoaded!==e.level||this.waitForCdnTuneIn(i.details))&&(this.state=Vt)}},c.onLevelLoaded=function(t,e){var r,i=this.levels,a=e.level,s=e.details,o=s.totalduration;if(i){this.log("Level "+a+" loaded ["+s.startSN+","+s.endSN+"], cc ["+s.startCC+", "+s.endCC+"] duration:"+o);var l=this.fragCurrent;!l||this.state!==Mt&&this.state!==Ft||l.level!==e.level&&l.loader&&(this.state=xt,l.loader.abort());var u=i[a],h=0;if(s.live||null!==(r=u.details)&&void 0!==r&&r.live){if(s.fragments[0]||(s.deltaUpdateFailed=!0),s.deltaUpdateFailed)return;h=this.alignPlaylists(s,u.details)}if(u.details=s,this.levelLastLoaded=a,this.hls.trigger(n.a.LEVEL_UPDATED,{details:s,level:a}),this.state===Vt){if(this.waitForCdnTuneIn(s))return;this.state=xt}this.startFragRequested?s.live&&this.synchronizeToLiveEdge(s):this.setStartPosition(s,h),this.tick()}else this.warn("Levels were reset while loading level "+a)},c._handleFragmentLoadProgress=function(t){var e,r=t.frag,i=t.part,a=t.payload,n=this.levels;if(n){var s=n[r.level],o=s.details;if(o){var l=s.videoCodec,u=o.PTSKnown||!o.live,h=null===(e=o.initSegment)||void 0===e?void 0:e.data,d=this._getAudioCodec(s),c=this.transmuxer=this.transmuxer||new Jt(this.hls,A.MAIN,this._handleTransmuxComplete.bind(this),this._handleTransmuxerFlush.bind(this)),f=i?i.index:-1,g=-1!==f,v=new ut(r.level,r.sn,r.stats.chunkCount,a.byteLength,f,g),p=this.initPTS[r.cc];c.push(a,h,d,l,r,i,o.totalduration,u,v,p)}else this.warn("Dropping fragment "+r.sn+" of level "+r.level+" after level details were reset")}else this.warn("Levels were reset while fragment load was in progress. Fragment "+r.sn+" of level "+r.level+" will not be buffered")},c.onAudioTrackSwitching=function(t,e){var r=this.altAudio,i=!!e.url,a=e.id;if(!i){if(this.mediaBuffer!==this.media){this.log("Switching on main audio, use media.buffered to schedule main fragment loading"),this.mediaBuffer=this.media;var s=this.fragCurrent;null!=s&&s.loader&&(this.log("Switching to main audio track, cancel main fragment load"),s.loader.abort()),this.resetTransmuxer(),this.resetLoadingState()}else this.audioOnly&&this.resetTransmuxer();var o=this.hls;r&&o.trigger(n.a.BUFFER_FLUSHING,{startOffset:0,endOffset:Number.POSITIVE_INFINITY,type:"audio"}),o.trigger(n.a.AUDIO_TRACK_SWITCHED,{id:a})}},c.onAudioTrackSwitched=function(t,e){var r=e.id,i=!!this.hls.audioTracks[r].url;if(i){var a=this.videoBuffer;a&&this.mediaBuffer!==a&&(this.log("Switching on alternate audio, use video.buffered to schedule main fragment loading"),this.mediaBuffer=a)}this.altAudio=i,this.tick()},c.onBufferCreated=function(t,e){var r,i,a=e.tracks,n=!1;for(var s in a){var o=a[s];if("main"===o.id){if(i=s,r=o,"video"===s){var l=a[s];l&&(this.videoBuffer=l.buffer)}}else n=!0}n&&r?(this.log("Alternate track found, use "+i+".buffered to schedule main fragment loading"),this.mediaBuffer=r.buffer):this.mediaBuffer=this.media},c.onFragBuffered=function(t,e){var r=e.frag,i=e.part;if(!r||r.type===A.MAIN){if(this.fragContextChanged(r))return this.warn("Fragment "+r.sn+(i?" p: "+i.index:"")+" of level "+r.level+" finished buffering, but was aborted. state: "+this.state),void(this.state===Bt&&(this.state=xt));var a=i?i.stats:r.stats;this.fragLastKbps=Math.round(8*a.total/(a.buffering.end-a.loading.first)),"initSegment"!==r.sn&&(this.fragPrevious=r),this.fragBufferedComplete(r,i)}},c.onError=function(t,e){switch(e.details){case s.a.FRAG_LOAD_ERROR:case s.a.FRAG_LOAD_TIMEOUT:case s.a.KEY_LOAD_ERROR:case s.a.KEY_LOAD_TIMEOUT:this.onFragmentOrKeyLoadError(A.MAIN,e);break;case s.a.LEVEL_LOAD_ERROR:case s.a.LEVEL_LOAD_TIMEOUT:this.state!==jt&&(e.fatal?(this.warn(""+e.details),this.state=jt):e.levelRetry||this.state!==Vt||(this.state=xt));break;case s.a.BUFFER_FULL_ERROR:if("main"===e.parent&&(this.state===Ut||this.state===Bt))!!this.media&<.isBuffered(this.media,this.media.currentTime)&<.isBuffered(this.media,this.media.currentTime+.5)?(this.reduceMaxBufferLength(),this.state=xt):(this.warn("buffer full error also media.currentTime is not buffered, flush everything"),this.immediateLevelSwitch())}},c.checkBuffer=function(){var t=this.media,e=this.gapController;if(t&&e&&t.readyState){var r=lt.getBuffered(t);!this.loadedmetadata&&r.length?(this.loadedmetadata=!0,this.seekToStartPos()):e.poll(this.lastCurrentTime),this.lastCurrentTime=t.currentTime}},c.onFragLoadEmergencyAborted=function(){this.state=xt,this.loadedmetadata||(this.startFragRequested=!1,this.nextLoadPosition=this.startPosition),this.tick()},c.onBufferFlushed=function(t,e){var r=e.type;if(r!==u.a.AUDIO||this.audioOnly&&!this.altAudio){var i=(r===u.a.VIDEO?this.videoBuffer:this.mediaBuffer)||this.media;this.afterBufferFlushed(i,r)}},c.onLevelsUpdated=function(t,e){this.levels=e.levels},c.swapAudioCodec=function(){this.audioCodecSwap=!this.audioCodecSwap},c.seekToStartPos=function(){var t=this.media,e=t.currentTime,r=this.startPosition;if(r>=0&&e0&&a1&&!1===t.seeking){var r=t.currentTime;if(lt.isBuffered(t,r)?e=this.getAppendedFrag(r):lt.isBuffered(t,r+.1)&&(e=this.getAppendedFrag(r+.1)),e){var i=this.fragPlaying,a=e.level;i&&e.sn===i.sn&&i.level===a&&e.urlId===i.urlId||(this.hls.trigger(n.a.FRAG_CHANGED,{frag:e}),i&&i.level===a||this.hls.trigger(n.a.LEVEL_SWITCHED,{level:a}),this.fragPlaying=e)}}},l=i,(h=[{key:"nextLevel",get:function(){var t=this.nextBufferedFrag;return t?t.level:-1}},{key:"currentLevel",get:function(){var t=this.media;if(t){var e=this.getAppendedFrag(t.currentTime);if(e)return e.level}return-1}},{key:"nextBufferedFrag",get:function(){var t=this.media;if(t){var e=this.getAppendedFrag(t.currentTime);return this.followingBufferedFrag(e)}return null}},{key:"forceStartLoad",get:function(){return this._forceStartLoad}}])&&te(l.prototype,h),d&&te(l,d),i}(Wt),ie=function(){function t(t,e,r){void 0===e&&(e=0),void 0===r&&(r=0),this.halfLife=void 0,this.alpha_=void 0,this.estimate_=void 0,this.totalWeight_=void 0,this.halfLife=t,this.alpha_=t?Math.exp(Math.log(.5)/t):0,this.estimate_=e,this.totalWeight_=r}var e=t.prototype;return e.sample=function(t,e){var r=Math.pow(this.alpha_,t);this.estimate_=e*(1-r)+r*this.estimate_,this.totalWeight_+=t},e.getTotalWeight=function(){return this.totalWeight_},e.getEstimate=function(){if(this.alpha_){var t=1-Math.pow(this.alpha_,this.totalWeight_);if(t)return this.estimate_/t}return this.estimate_},t}(),ae=function(){function t(t,e,r){this.defaultEstimate_=void 0,this.minWeight_=void 0,this.minDelayMs_=void 0,this.slow_=void 0,this.fast_=void 0,this.defaultEstimate_=r,this.minWeight_=.001,this.minDelayMs_=50,this.slow_=new ie(t),this.fast_=new ie(e)}var e=t.prototype;return e.update=function(t,e){var r=this.slow_,i=this.fast_;this.slow_.halfLife!==t&&(this.slow_=new ie(t,r.getEstimate(),r.getTotalWeight())),this.fast_.halfLife!==e&&(this.fast_=new ie(e,i.getEstimate(),i.getTotalWeight()))},e.sample=function(t,e){var r=(t=Math.max(t,this.minDelayMs_))/1e3,i=8*e/r;this.fast_.sample(r,i),this.slow_.sample(r,i)},e.canEstimate=function(){var t=this.fast_;return t&&t.getTotalWeight()>=this.minWeight_},e.getEstimate=function(){return this.canEstimate()?Math.min(this.fast_.getEstimate(),this.slow_.getEstimate()):this.defaultEstimate_},e.destroy=function(){},t}();function ne(t,e){for(var r=0;r=2*h/c||y<=E)){var b,S=Number.POSITIVE_INFINITY;for(b=t.level-1;b>g;b--){if((S=h*f[b].maxBitrate/(6.4*m))=y)){var L=this.bwEstimator.getEstimate();o.b.warn("Fragment "+t.sn+(e?" part "+e.index:"")+" of level "+t.level+" is loading too slowly and will cause an underbuffer; aborting and switching to level "+b+"\n Current BW estimate: "+(Object(a.a)(L)?(L/1024).toFixed(3):"Unknown")+" Kb/s\n Estimated load time for current fragment: "+y.toFixed(3)+" s\n Estimated load time for the next fragment: "+S.toFixed(3)+" s\n Time to underbuffer: "+E.toFixed(3)+" s"),r.nextLoadLevel=b,this.bwEstimator.sample(d,u.loaded),this.clearTimer(),t.loader&&(this.fragCurrent=this.partCurrent=null,t.loader.abort()),r.trigger(n.a.FRAG_LOAD_EMERGENCY_ABORTED,{frag:t,part:e,stats:u})}}}}}},l.onFragLoaded=function(t,e){var r=e.frag,i=e.part;if(r.type===A.MAIN&&Object(a.a)(r.sn)){var s=i?i.stats:r.stats,o=i?i.duration:r.duration;if(this.clearTimer(),this.lastLoadedFragLevel=r.level,this._nextAutoLevel=-1,this.hls.config.abrMaxWithRealBitrate){var l=this.hls.levels[r.level],u=(l.loaded?l.loaded.bytes:0)+s.loaded,h=(l.loaded?l.loaded.duration:0)+o;l.loaded={bytes:u,duration:h},l.realBitrate=Math.round(8*u/h)}if(r.bitrateTest){var d={stats:s,frag:r,part:i,id:r.type};this.onFragBuffered(n.a.FRAG_BUFFERED,d),r.bitrateTest=!1}}},l.onFragBuffered=function(t,e){var r=e.frag,i=e.part,a=i?i.stats:r.stats;if(!a.aborted&&r.type===A.MAIN&&"initSegment"!==r.sn){var n=a.parsing.end-a.loading.start;this.bwEstimator.sample(n,a.loaded),a.bwEstimate=this.bwEstimator.getEstimate(),r.bitrateTest?this.bitrateTestDelay=n/1e3:this.bitrateTestDelay=0}},l.onError=function(t,e){switch(e.details){case s.a.FRAG_LOAD_ERROR:case s.a.FRAG_LOAD_TIMEOUT:this.clearTimer()}},l.clearTimer=function(){self.clearInterval(this.timer),this.timer=void 0},l.getNextABRAutoLevel=function(){var t=this.fragCurrent,e=this.partCurrent,r=this.hls,i=r.maxAutoLevel,a=r.config,n=r.minAutoLevel,s=r.media,l=e?e.duration:t?t.duration:0,u=s?s.currentTime:0,h=s&&0!==s.playbackRate?Math.abs(s.playbackRate):1,d=this.bwEstimator?this.bwEstimator.getEstimate():a.abrEwmaDefaultEstimate,c=(lt.bufferInfo(s,u,a.maxBufferHole).end-u)/h,f=this.findBestLevel(d,n,i,c,a.abrBandWidthFactor,a.abrBandWidthUpFactor);if(f>=0)return f;o.b.trace((c?"rebuffering expected":"buffer is empty")+", finding optimal quality level");var g=l?Math.min(l,a.maxStarvationDelay):a.maxStarvationDelay,v=a.abrBandWidthFactor,p=a.abrBandWidthUpFactor;if(!c){var m=this.bitrateTestDelay;if(m)g=(l?Math.min(l,a.maxLoadingDelay):a.maxLoadingDelay)-m,o.b.trace("bitrate test took "+Math.round(1e3*m)+"ms, set first fragment max fetchDuration to "+Math.round(1e3*g)+" ms"),v=p=1}return f=this.findBestLevel(d,n,i,c+g,v,p),Math.max(f,0)},l.findBestLevel=function(t,e,r,i,a,n){for(var s,l=this.fragCurrent,u=this.partCurrent,h=this.lastLoadedFragLevel,d=this.hls.levels,c=d[h],f=!(null==c||null===(s=c.details)||void 0===s||!s.live),g=null==c?void 0:c.codecSet,v=u?u.duration:l?l.duration:0,p=r;p>=e;p--){var m=d[p];if(m&&(!g||m.codecSet===g)){var y=m.details,T=(u?null==y?void 0:y.partTarget:null==y?void 0:y.averagetargetduration)||v,E=void 0;E=p<=h?a*t:n*t;var b=d[p].maxBitrate,S=b*T/E;if(o.b.trace("level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: "+p+"/"+Math.round(E)+"/"+b+"/"+T+"/"+i+"/"+S),E>b&&(!S||f&&!this.bitrateTestDelay||S0&&-1===t?(this.log("Override startPosition with lastCurrentTime @"+e.toFixed(3)),this.state=xt):(this.loadedmetadata=!1,this.state=Nt),this.nextLoadPosition=this.startPosition=this.lastCurrentTime=t,this.tick()},l.doTick=function(){switch(this.state){case xt:this.doTickIdle();break;case Nt:var e,r=this.levels,i=this.trackId,a=null==r||null===(e=r[i])||void 0===e?void 0:e.details;if(a){if(this.waitForCdnTuneIn(a))break;this.state=Ht}break;case Ft:var n,s=performance.now(),l=this.retryDate;(!l||s>=l||null!==(n=this.media)&&void 0!==n&&n.seeking)&&(this.log("RetryDate reached, switch back to IDLE state"),this.state=xt);break;case Ht:var u=this.waitingData;if(u){var h=u.frag,d=u.part,c=u.cache,f=u.complete;if(void 0!==this.initPTS[h.cc]){this.waitingData=null,this.state=Mt;var g={frag:h,part:d,payload:c.flush(),networkDetails:null};this._handleFragmentLoadProgress(g),f&&t.prototype._handleFragmentLoadComplete.call(this,g)}else if(this.videoTrackCC!==this.waitingVideoCC)o.b.log("Waiting fragment cc ("+h.cc+") cancelled because video is at cc "+this.videoTrackCC),this.clearWaitingFragment();else{var v=lt.bufferInfo(this.mediaBuffer,this.media.currentTime,this.config.maxBufferHole);mt(v.end,this.config.maxFragLookUpTolerance,h)<0&&(o.b.log("Waiting fragment cc ("+h.cc+") @ "+h.start+" cancelled because another fragment at "+v.end+" is needed"),this.clearWaitingFragment())}}else this.state=xt}this.onTickEnd()},l.clearWaitingFragment=function(){var t=this.waitingData;t&&(this.fragmentTracker.removeFragment(t.frag),this.waitingData=null,this.waitingVideoCC=-1,this.state=xt)},l.onTickEnd=function(){var t=this.media;if(t&&t.readyState){var e=(this.mediaBuffer?this.mediaBuffer:t).buffered;!this.loadedmetadata&&e.length&&(this.loadedmetadata=!0),this.lastCurrentTime=t.currentTime}},l.doTickIdle=function(){var t,e,r=this.hls,i=this.levels,s=this.media,o=this.trackId,l=r.config;if(i&&i[o]&&(s||!this.startFragRequested&&l.startFragPrefetch)){var u=this.getLoadPosition();if(Object(a.a)(u)){var h=i[o].details;if(!h||h.live&&this.levelLastLoaded!==o||this.waitForCdnTuneIn(h))this.state=Nt;else{var d=h.initSegment,c=0;if(!d||d.data){var f=this.mediaBuffer?this.mediaBuffer:this.media,g=this.videoBuffer?this.videoBuffer:this.media,v=u=E&&!b)return;if(!b&&this._streamEnded(p,h))return r.trigger(n.a.BUFFER_EOS,{type:"audio"}),void(this.state=Kt);var S=h.fragments[0].start;if(c=p.end,b&&(c=u,h.PTSKnown&&uS||p.nextStart)&&(this.log("Alt audio track ahead of main track, seek to start of alt audio track"),s.currentTime=S+.05)),!(d=this.getNextFragment(c,h)))return}"identity"!==(null===(t=d.decryptdata)||void 0===t?void 0:t.keyFormat)||null!==(e=d.decryptdata)&&void 0!==e&&e.key?this.loadFragment(d,h,c):(this.log("Loading key for "+d.sn+" of ["+h.startSN+" ,"+h.endSN+"],track "+o),this.state=Pt,r.trigger(n.a.KEY_LOADING,{frag:d}))}}}},l.onMediaDetaching=function(){this.videoBuffer=null,t.prototype.onMediaDetaching.call(this)},l.onAudioTracksUpdated=function(t,e){var r=e.audioTracks;this.resetTransmuxer(),this.levels=r.map((function(t){return new H(t)}))},l.onAudioTrackSwitching=function(t,e){var r=!!e.url;this.trackId=e.id;var i=this.fragCurrent;null!=i&&i.loader&&i.loader.abort(),this.fragCurrent=null,this.clearWaitingFragment(),r?this.setInterval(100):this.resetTransmuxer(),r?(this.audioSwitch=!0,this.state=xt):this.state=Ot,this.tick()},l.onManifestLoading=function(){this.mainDetails=null,this.fragmentTracker.removeAllFragments(),this.startPosition=this.lastCurrentTime=0},l.onLevelLoaded=function(t,e){if(null===this.mainDetails){var r=this.mainDetails=e.details,i=this.levelLastLoaded;if(null!==i&&this.levels&&-1===this.startPosition&&r.live){var a=this.levels[i];if(!a.details||!a.details.fragments[0])return;ft(a.details,r),this.setStartPosition(a.details,a.details.fragments[0].start)}}},l.onAudioTrackLoaded=function(t,e){var r,i=this.levels,a=e.details,n=e.id;if(i){this.log("Track "+n+" loaded ["+a.startSN+","+a.endSN+"],duration:"+a.totalduration);var s=i[n],o=0;if(a.live||null!==(r=s.details)&&void 0!==r&&r.live){var l;if(a.fragments[0]||(a.deltaUpdateFailed=!0),a.deltaUpdateFailed)return;!s.details&&null!==(l=this.mainDetails)&&void 0!==l&&l.hasProgramDateTime&&a.hasProgramDateTime?(ft(a,this.mainDetails),o=a.fragments[0].start):o=this.alignPlaylists(a,s.details)}s.details=a,this.levelLastLoaded=n,this.startFragRequested||!this.mainDetails&&a.live||this.setStartPosition(s.details,o),this.state!==Nt||this.waitForCdnTuneIn(a)||(this.state=xt),this.tick()}else this.warn("Audio tracks were reset while loading level "+n)},l._handleFragmentLoadProgress=function(t){var e,r=t.frag,i=t.part,a=t.payload,n=this.config,s=this.trackId,l=this.levels;if(l){var u=l[s],h=u.details,d=n.defaultAudioCodec||u.audioCodec||"mp4a.40.2",c=this.transmuxer;c||(c=this.transmuxer=new Jt(this.hls,A.AUDIO,this._handleTransmuxComplete.bind(this),this._handleTransmuxerFlush.bind(this)));var f=this.initPTS[r.cc],g=null===(e=h.initSegment)||void 0===e?void 0:e.data;if(void 0!==f){var v=i?i.index:-1,p=-1!==v,m=new ut(r.level,r.sn,r.stats.chunkCount,a.byteLength,v,p);c.push(a,g,d,"",r,i,h.totalduration,!1,m,f)}else{o.b.log("Unknown video PTS for cc "+r.cc+", waiting for video PTS before demuxing audio frag "+r.sn+" of ["+h.startSN+" ,"+h.endSN+"],track "+s),(this.waitingData=this.waitingData||{frag:r,part:i,cache:new oe.a,complete:!1}).cache.push(new Uint8Array(a)),this.waitingVideoCC=this.videoTrackCC,this.state=Ht}}else this.warn("Audio tracks were reset while fragment load was in progress. Fragment "+r.sn+" of level "+r.level+" will not be buffered")},l._handleFragmentLoadComplete=function(e){this.waitingData?this.waitingData.complete=!0:t.prototype._handleFragmentLoadComplete.call(this,e)},l.onBufferReset=function(){this.mediaBuffer=this.videoBuffer=null,this.loadedmetadata=!1},l.onBufferCreated=function(t,e){var r=e.tracks.audio;r&&(this.mediaBuffer=r.buffer),e.tracks.video&&(this.videoBuffer=e.tracks.video.buffer)},l.onFragBuffered=function(t,e){var r=e.frag,i=e.part;r.type===A.AUDIO&&(this.fragContextChanged(r)?this.warn("Fragment "+r.sn+(i?" p: "+i.index:"")+" of level "+r.level+" finished buffering, but was aborted. state: "+this.state+", audioSwitch: "+this.audioSwitch):("initSegment"!==r.sn&&(this.fragPrevious=r,this.audioSwitch&&(this.audioSwitch=!1,this.hls.trigger(n.a.AUDIO_TRACK_SWITCHED,{id:this.trackId}))),this.fragBufferedComplete(r,i)))},l.onError=function(e,r){switch(r.details){case s.a.FRAG_LOAD_ERROR:case s.a.FRAG_LOAD_TIMEOUT:case s.a.KEY_LOAD_ERROR:case s.a.KEY_LOAD_TIMEOUT:this.onFragmentOrKeyLoadError(A.AUDIO,r);break;case s.a.AUDIO_TRACK_LOAD_ERROR:case s.a.AUDIO_TRACK_LOAD_TIMEOUT:this.state!==jt&&this.state!==Ot&&(this.state=r.fatal?jt:xt,this.warn(r.details+" while loading frag, switching to "+this.state+" state"));break;case s.a.BUFFER_FULL_ERROR:if("audio"===r.parent&&(this.state===Ut||this.state===Bt)){var i=this.mediaBuffer,a=this.media.currentTime;i&<.isBuffered(i,a)&<.isBuffered(i,a+.5)?(this.reduceMaxBufferLength(),this.state=xt):(this.warn("Buffer full error also media.currentTime is not buffered, flush audio buffer"),this.fragCurrent=null,t.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio"))}}},l.onBufferFlushed=function(t,e){var r=e.type;if(r===u.a.AUDIO){var i=this.mediaBuffer?this.mediaBuffer:this.media;this.afterBufferFlushed(i,r)}},l._handleTransmuxComplete=function(t){var e,r="audio",i=this.hls,a=t.remuxResult,s=t.chunkMeta,o=this.getCurrentContext(s);if(!o)return this.warn("The loading context changed while buffering fragment "+s.sn+" of level "+s.level+". This chunk will not be buffered."),void this.resetLiveStartWhenNotLoaded(s.level);var l=o.frag,h=o.part,d=a.audio,c=a.text,f=a.id3,g=a.initSegment;if(!this.fragContextChanged(l)){if(this.state=Ut,this.audioSwitch&&d&&this.completeAudioSwitch(),null!=g&&g.tracks&&(this._bufferInitSegment(g.tracks,l,s),i.trigger(n.a.FRAG_PARSING_INIT_SEGMENT,{frag:l,id:r,tracks:g.tracks})),d){var v=d.startPTS,p=d.endPTS,m=d.startDTS,y=d.endDTS;h&&(h.elementaryStreams[u.a.AUDIO]={startPTS:v,endPTS:p,startDTS:m,endDTS:y}),l.setElementaryStreamInfo(u.a.AUDIO,v,p,m,y),this.bufferFragmentData(d,l,h,s)}if(null!=f&&null!==(e=f.samples)&&void 0!==e&&e.length){var T=le({frag:l,id:r},f);i.trigger(n.a.FRAG_PARSING_METADATA,T)}if(c){var E=le({frag:l,id:r},c);i.trigger(n.a.FRAG_PARSING_USERDATA,E)}}},l._bufferInitSegment=function(t,e,r){if(this.state===Ut){t.video&&delete t.video;var i=t.audio;if(i){i.levelCodec=i.codec,i.id="audio",this.log("Init audio buffer, container:"+i.container+", codecs[parsed]=["+i.codec+"]"),this.hls.trigger(n.a.BUFFER_CODECS,t);var a=i.initSegment;if(null!=a&&a.byteLength){var s={type:"audio",frag:e,part:null,chunkMeta:r,parent:e.type,data:a};this.hls.trigger(n.a.BUFFER_APPENDING,s)}this.tick()}}},l.loadFragment=function(e,r,i){var n=this.fragmentTracker.getState(e);this.fragCurrent=e,(this.audioSwitch||n===tt.NOT_LOADED||n===tt.PARTIAL)&&("initSegment"===e.sn?this._loadInitSegment(e):r.live&&!Object(a.a)(this.initPTS[e.cc])?(this.log("Waiting for video PTS in continuity counter "+e.cc+" of live stream before loading audio fragment "+e.sn+" of level "+this.trackId),this.state=Ht):(this.startFragRequested=!0,t.prototype.loadFragment.call(this,e,r,i)))},l.completeAudioSwitch=function(){var e=this.hls,r=this.media,i=this.trackId;r&&(this.log("Switching audio track : flushing all audio"),t.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio")),this.audioSwitch=!1,e.trigger(n.a.AUDIO_TRACK_SWITCHED,{id:i})},i}(Wt);function de(t,e){for(var r=0;r=e.length)this.warn("Invalid id passed to audio-track controller");else{this.clearTimer();var r=e[this.trackId];this.log("Now switching to audio-track index "+t);var i=e[t],a=i.id,s=i.groupId,o=void 0===s?"":s,l=i.name,u=i.type,h=i.url;if(this.trackId=t,this.trackName=l,this.selectDefaultTrack=!1,this.hls.trigger(n.a.AUDIO_TRACK_SWITCHING,{id:a,groupId:o,name:l,type:u,url:h}),!i.details||i.details.live){var d=this.switchParams(i.url,null==r?void 0:r.details);this.loadPlaylist(d)}}},u.selectInitialTrack=function(){this.tracksInGroup;var t=this.trackName,e=this.findTrackId(t)||this.findTrackId();-1!==e?this.setAudioTrack(e):(this.warn("No track found for running audio group-ID: "+this.groupId),this.hls.trigger(n.a.ERROR,{type:s.b.MEDIA_ERROR,details:s.a.AUDIO_TRACK_LOAD_ERROR,fatal:!0}))},u.findTrackId=function(t){for(var e=this.tracksInGroup,r=0;r=a[o].start&&s<=a[o].end){n=a[o];break}var l=r.start+r.duration;n?n.end=l:(n={start:s,end:l},a.push(n))}}},u.onMediaAttached=function(t,e){var r=e.media;this.media=r,this.state=xt},u.onMediaDetaching=function(){var t=this;this.media&&(this.fragmentTracker.removeAllFragments(),this.fragPrevious=null,this.currentTrackId=-1,this.levels.forEach((function(e){t.tracksBuffered[e.id]=[]})),this.media=null,this.mediaBuffer=null,this.state=Ot)},u.onError=function(t,e){var r,i=e.frag;i&&i.type===A.SUBTITLE&&(null!==(r=this.fragCurrent)&&void 0!==r&&r.loader&&this.fragCurrent.loader.abort(),this.state=xt)},u.onSubtitleTracksUpdated=function(t,e){var r=this,i=e.subtitleTracks;this.tracksBuffered=[],this.levels=i.map((function(t){return new H(t)})),this.fragmentTracker.removeAllFragments(),this.fragPrevious=null,this.levels.forEach((function(t){r.tracksBuffered[t.id]=[]})),this.mediaBuffer=null},u.onSubtitleTrackSwitch=function(t,e){if(this.currentTrackId=e.id,this.levels.length&&-1!==this.currentTrackId){var r=this.levels[this.currentTrackId];null!=r&&r.details?(this.mediaBuffer=this.mediaBufferTimeRanges,this.setInterval(500)):this.mediaBuffer=null}else this.clearInterval()},u.onSubtitleTrackLoaded=function(t,e){var r,i=e.id,a=e.details,n=this.currentTrackId,s=this.levels;if(s.length&&a){var o=s[n];if(!(i>=s.length||i!==n)&&o){if(this.mediaBuffer=this.mediaBufferTimeRanges,a.live||null!==(r=o.details)&&void 0!==r&&r.live){if(a.deltaUpdateFailed)return;this.alignPlaylists(a,o.details)}o.details=a,this.levelLastLoaded=i,this.setInterval(500)}}},u._handleFragmentLoadComplete=function(t){var e=t.frag,r=t.payload,i=e.decryptdata,a=this.hls;if(!this.fragContextChanged(e)&&r&&r.byteLength>0&&i&&i.key&&i.iv&&"AES-128"===i.method){var s=performance.now();this.decrypter.webCryptoDecrypt(new Uint8Array(r),i.key.buffer,i.iv.buffer).then((function(t){var r=performance.now();a.trigger(n.a.FRAG_DECRYPTED,{frag:e,payload:t,stats:{tstart:s,tdecrypt:r}})}))}},u.doTick=function(){if(this.media){if(this.state===xt){var t,e=this.config,r=this.currentTrackId,i=this.fragmentTracker,a=this.media,s=this.levels;if(!s.length||!s[r]||!s[r].details)return;var l=e.maxBufferHole,u=e.maxFragLookUpTolerance,h=Math.min(e.maxBufferLength,e.maxMaxBufferLength),d=lt.bufferedInfo(this.mediaBufferTimeRanges,a.currentTime,l),c=d.end;if(d.len>h)return;var f,g=s[r].details,v=g.fragments,p=v.length,m=v[p-1].start+v[p-1].duration,y=this.fragPrevious;c-1&&(this.subtitleTrack=this.queuedDefaultTrack,this.queuedDefaultTrack=-1),this.useTextTrackPolling=!(this.media.textTracks&&"onchange"in this.media.textTracks),this.useTextTrackPolling?(self.clearInterval(this.subtitlePollingInterval),this.subtitlePollingInterval=self.setInterval((function(){r.trackChangeListener()}),500)):this.media.textTracks.addEventListener("change",this.trackChangeListener))},l.onMediaDetaching=function(){this.media&&(this.useTextTrackPolling?self.clearInterval(this.subtitlePollingInterval):this.media.textTracks.removeEventListener("change",this.trackChangeListener),this.trackId>-1&&(this.queuedDefaultTrack=this.trackId),Te(this.media.textTracks).forEach((function(t){P(t)})),this.subtitleTrack=-1,this.media=null)},l.onManifestLoading=function(){this.tracks=[],this.groupId=null,this.tracksInGroup=[],this.trackId=-1,this.selectDefaultTrack=!0},l.onManifestParsed=function(t,e){this.tracks=e.subtitleTracks},l.onSubtitleTrackLoaded=function(t,e){var r=e.id,i=e.details,a=this.trackId,n=this.tracksInGroup[a];if(n){var s=n.details;n.details=e.details,this.log("subtitle track "+r+" loaded ["+i.startSN+"-"+i.endSN+"]"),r===this.trackId&&(this.retryCount=0,this.playlistLoaded(r,e,s))}else this.warn("Invalid subtitle track id "+r)},l.onLevelLoading=function(t,e){this.switchLevel(e.level)},l.onLevelSwitching=function(t,e){this.switchLevel(e.level)},l.switchLevel=function(t){var e=this.hls.levels[t];if(null!=e&&e.textGroupIds){var r=e.textGroupIds[e.urlId];if(this.groupId!==r){var i=this.tracksInGroup?this.tracksInGroup[this.trackId]:void 0,a=this.findTrackId(null==i?void 0:i.name)||this.findTrackId(),s=this.tracks.filter((function(t){return!r||t.groupId===r}));this.groupId=r,this.tracksInGroup=s;var o={subtitleTracks:s};this.log("Updating subtitle tracks, "+s.length+' track(s) found in "'+r+'" group-id'),this.hls.trigger(n.a.SUBTITLE_TRACKS_UPDATED,o),-1!==a&&this.setSubtitleTrack(a,i)}}},l.findTrackId=function(t){for(var e=this.tracksInGroup,r=0;r=i.length)){this.clearTimer();var a=i[t];if(this.log("Switching to subtitle track "+t),this.trackId=t,a){var s=a.id,o=a.groupId,l=void 0===o?"":o,u=a.name,h=a.type,d=a.url;this.hls.trigger(n.a.SUBTITLE_TRACK_SWITCH,{id:s,groupId:l,name:u,type:h,url:d});var c=this.switchParams(a.url,null==e?void 0:e.details);this.loadPlaylist(c)}else this.hls.trigger(n.a.SUBTITLE_TRACK_SWITCH,{id:t})}}else this.queuedDefaultTrack=t},l.onTextTracksChanged=function(){if(this.media&&this.hls.config.renderTextTracksNatively){for(var t=-1,e=Te(this.media.textTracks),r=0;r0||Object.keys(this.pendingTracks).length>0},e.destroy=function(){this.unregisterListeners(),this.details=null},e.registerListeners=function(){var t=this.hls;t.on(n.a.MEDIA_ATTACHING,this.onMediaAttaching,this),t.on(n.a.MEDIA_DETACHING,this.onMediaDetaching,this),t.on(n.a.MANIFEST_PARSED,this.onManifestParsed,this),t.on(n.a.BUFFER_RESET,this.onBufferReset,this),t.on(n.a.BUFFER_APPENDING,this.onBufferAppending,this),t.on(n.a.BUFFER_CODECS,this.onBufferCodecs,this),t.on(n.a.BUFFER_EOS,this.onBufferEos,this),t.on(n.a.BUFFER_FLUSHING,this.onBufferFlushing,this),t.on(n.a.LEVEL_UPDATED,this.onLevelUpdated,this),t.on(n.a.FRAG_PARSED,this.onFragParsed,this),t.on(n.a.FRAG_CHANGED,this.onFragChanged,this)},e.unregisterListeners=function(){var t=this.hls;t.off(n.a.MEDIA_ATTACHING,this.onMediaAttaching,this),t.off(n.a.MEDIA_DETACHING,this.onMediaDetaching,this),t.off(n.a.MANIFEST_PARSED,this.onManifestParsed,this),t.off(n.a.BUFFER_RESET,this.onBufferReset,this),t.off(n.a.BUFFER_APPENDING,this.onBufferAppending,this),t.off(n.a.BUFFER_CODECS,this.onBufferCodecs,this),t.off(n.a.BUFFER_EOS,this.onBufferEos,this),t.off(n.a.BUFFER_FLUSHING,this.onBufferFlushing,this),t.off(n.a.LEVEL_UPDATED,this.onLevelUpdated,this),t.off(n.a.FRAG_PARSED,this.onFragParsed,this),t.off(n.a.FRAG_CHANGED,this.onFragChanged,this)},e._initSourceBuffer=function(){this.sourceBuffer={},this.operationQueue=new Se(this.sourceBuffer),this.listeners={audio:[],video:[],audiovideo:[]}},e.onManifestParsed=function(t,e){var r=2;(e.audio&&!e.video||!e.altAudio)&&(r=1),this.bufferCodecEventsExpected=this._bufferCodecEventsTotal=r,this.details=null,o.b.log(this.bufferCodecEventsExpected+" bufferCodec event(s) expected")},e.onMediaAttaching=function(t,e){var r=this.media=e.media;if(r&&Le){var i=this.mediaSource=new Le;i.addEventListener("sourceopen",this._onMediaSourceOpen),i.addEventListener("sourceended",this._onMediaSourceEnded),i.addEventListener("sourceclose",this._onMediaSourceClose),r.src=self.URL.createObjectURL(i),this._objectUrl=r.src}},e.onMediaDetaching=function(){var t=this.media,e=this.mediaSource,r=this._objectUrl;if(e){if(o.b.log("[buffer-controller]: media source detaching"),"open"===e.readyState)try{e.endOfStream()}catch(t){o.b.warn("[buffer-controller]: onMediaDetaching: "+t.message+" while calling endOfStream")}this.onBufferReset(),e.removeEventListener("sourceopen",this._onMediaSourceOpen),e.removeEventListener("sourceended",this._onMediaSourceEnded),e.removeEventListener("sourceclose",this._onMediaSourceClose),t&&(r&&self.URL.revokeObjectURL(r),t.src===r?(t.removeAttribute("src"),t.load()):o.b.warn("[buffer-controller]: media.src was changed by a third party - skip cleanup")),this.mediaSource=null,this.media=null,this._objectUrl=null,this.bufferCodecEventsExpected=this._bufferCodecEventsTotal,this.pendingTracks={},this.tracks={}}this.hls.trigger(n.a.MEDIA_DETACHED,void 0)},e.onBufferReset=function(){var t=this,e=this.sourceBuffer;this.getSourceBufferTypes().forEach((function(r){var i=e[r];try{i&&(t.removeBufferListeners(r),t.mediaSource&&t.mediaSource.removeSourceBuffer(i),e[r]=void 0)}catch(t){o.b.warn("[buffer-controller]: Failed to reset the "+r+" buffer",t)}})),this._initSourceBuffer()},e.onBufferCodecs=function(t,e){var r=this,i=Object.keys(this.sourceBuffer).length;Object.keys(e).forEach((function(t){if(i){var a=r.tracks[t];if(a&&"function"==typeof a.buffer.changeType){var n=e[t],s=n.codec,o=n.levelCodec,l=n.container;if((a.levelCodec||a.codec).replace(Ae,"$1")!==(o||s).replace(Ae,"$1")){var u=l+";codecs="+(o||s);r.appendChangeType(t,u)}}}else r.pendingTracks[t]=e[t]})),i||(this.bufferCodecEventsExpected=Math.max(this.bufferCodecEventsExpected-1,0),this.mediaSource&&"open"===this.mediaSource.readyState&&this.checkPendingTracks())},e.appendChangeType=function(t,e){var r=this,i=this.operationQueue,a={execute:function(){var a=r.sourceBuffer[t];a&&(o.b.log("[buffer-controller]: changing "+t+" sourceBuffer type to "+e),a.changeType(e)),i.shiftAndExecuteNext(t)},onStart:function(){},onComplete:function(){},onError:function(e){o.b.warn("[buffer-controller]: Failed to change "+t+" SourceBuffer type",e)}};i.append(a,t)},e.onBufferAppending=function(t,e){var r=this,i=this.hls,a=this.operationQueue,l=this.tracks,u=e.data,h=e.type,d=e.frag,c=e.part,f=e.chunkMeta,g=f.buffering[h],v=self.performance.now();g.start=v;var p=d.stats.buffering,m=c?c.stats.buffering:null;0===p.start&&(p.start=v),m&&0===m.start&&(m.start=v);var y=l.audio,T="audio"===h&&1===f.id&&"audio/mpeg"===(null==y?void 0:y.container),E={execute:function(){if(g.executeStart=self.performance.now(),T){var t=r.sourceBuffer[h];if(t){var e=d.start-t.timestampOffset;Math.abs(e)>=.1&&(o.b.log("[buffer-controller]: Updating audio SourceBuffer timestampOffset to "+d.start+" (delta: "+e+") sn: "+d.sn+")"),t.timestampOffset=d.start)}}r.appendExecutor(u,h)},onStart:function(){},onComplete:function(){var t=self.performance.now();g.executeEnd=g.end=t,0===p.first&&(p.first=t),m&&0===m.first&&(m.first=t);var e=r.sourceBuffer,i={};for(var a in e)i[a]=lt.getBuffered(e[a]);r.appendError=0,r.hls.trigger(n.a.BUFFER_APPENDED,{type:h,frag:d,part:c,chunkMeta:f,parent:d.type,timeRanges:i})},onError:function(t){o.b.error("[buffer-controller]: Error encountered while trying to append to the "+h+" SourceBuffer",t);var e={type:s.b.MEDIA_ERROR,parent:d.type,details:s.a.BUFFER_APPEND_ERROR,err:t,fatal:!1};t.code===DOMException.QUOTA_EXCEEDED_ERR?e.details=s.a.BUFFER_FULL_ERROR:(r.appendError++,e.details=s.a.BUFFER_APPEND_ERROR,r.appendError>i.config.appendErrorMaxRetry&&(o.b.error("[buffer-controller]: Failed "+i.config.appendErrorMaxRetry+" times to append segment in sourceBuffer"),e.fatal=!0)),i.trigger(n.a.ERROR,e)}};a.append(E,h)},e.onBufferFlushing=function(t,e){var r=this,i=this.operationQueue,a=function(t){return{execute:r.removeExecutor.bind(r,t,e.startOffset,e.endOffset),onStart:function(){},onComplete:function(){r.hls.trigger(n.a.BUFFER_FLUSHED,{type:t})},onError:function(e){o.b.warn("[buffer-controller]: Failed to remove from "+t+" SourceBuffer",e)}}};e.type?i.append(a(e.type),e.type):(i.append(a("audio"),"audio"),i.append(a("video"),"video"))},e.onFragParsed=function(t,e){var r=this,i=e.frag,a=e.part,s=[],l=a?a.elementaryStreams:i.elementaryStreams;l[u.a.AUDIOVIDEO]?s.push("audiovideo"):(l[u.a.AUDIO]&&s.push("audio"),l[u.a.VIDEO]&&s.push("video"));0===s.length&&o.b.warn("Fragments must have at least one ElementaryStreamType set. type: "+i.type+" level: "+i.level+" sn: "+i.sn),this.blockBuffers((function(){var t=self.performance.now();i.stats.buffering.end=t,a&&(a.stats.buffering.end=t);var e=a?a.stats:i.stats;r.hls.trigger(n.a.FRAG_BUFFERED,{frag:i,part:a,stats:e,id:i.type})}),s)},e.onFragChanged=function(t,e){this.flushBackBuffer()},e.onBufferEos=function(t,e){var r=this;this.getSourceBufferTypes().reduce((function(t,i){var a=r.sourceBuffer[i];return e.type&&e.type!==i||a&&!a.ended&&(a.ended=!0,o.b.log("[buffer-controller]: "+i+" sourceBuffer now EOS")),t&&!(a&&!a.ended)}),!0)&&this.blockBuffers((function(){var t=r.mediaSource;t&&"open"===t.readyState&&t.endOfStream()}))},e.onLevelUpdated=function(t,e){var r=e.details;r.fragments.length&&(this.details=r,this.getSourceBufferTypes().length?this.blockBuffers(this.updateMediaElementDuration.bind(this)):this.updateMediaElementDuration())},e.flushBackBuffer=function(){var t=this.hls,e=this.details,r=this.media,i=this.sourceBuffer;if(r&&null!==e){var s=this.getSourceBufferTypes();if(s.length){var o=e.live&&null!==t.config.liveBackBufferLength?t.config.liveBackBufferLength:t.config.backBufferLength;if(Object(a.a)(o)&&!(o<0)){var l=r.currentTime,u=e.levelTargetDuration,h=Math.max(o,u),d=Math.floor(l/u)*u-h;s.forEach((function(r){var a=i[r];if(a){var s=lt.getBuffered(a);s.length>0&&d>s.start(0)&&(t.trigger(n.a.BACK_BUFFER_REACHED,{bufferEnd:d}),e.live&&t.trigger(n.a.LIVE_BACK_BUFFER_REACHED,{bufferEnd:d}),t.trigger(n.a.BUFFER_FLUSHING,{startOffset:0,endOffset:d,type:r}))}}))}}}},e.updateMediaElementDuration=function(){if(this.details&&this.media&&this.mediaSource&&"open"===this.mediaSource.readyState){var t=this.details,e=this.hls,r=this.media,i=this.mediaSource,n=t.fragments[0].start+t.totalduration,s=r.duration,l=Object(a.a)(i.duration)?i.duration:0;t.live&&e.config.liveDurationInfinity?(o.b.log("[buffer-controller]: Media Source duration is set to Infinity"),i.duration=1/0,this.updateSeekableRange(t)):(n>l&&n>s||!Object(a.a)(s))&&(o.b.log("[buffer-controller]: Updating Media Source duration to "+n.toFixed(3)),i.duration=n)}},e.updateSeekableRange=function(t){var e=this.mediaSource,r=t.fragments;if(r.length&&t.live&&null!=e&&e.setLiveSeekableRange){var i=Math.max(0,r[0].start),a=Math.max(i,i+t.totalduration);e.setLiveSeekableRange(i,a)}},e.checkPendingTracks=function(){var t=this.bufferCodecEventsExpected,e=this.operationQueue,r=this.pendingTracks,i=Object.keys(r).length;if(i&&!t||2===i){this.createSourceBuffers(r),this.pendingTracks={};var a=Object.keys(this.sourceBuffer);if(0===a.length)return void this.hls.trigger(n.a.ERROR,{type:s.b.MEDIA_ERROR,details:s.a.BUFFER_INCOMPATIBLE_CODECS_ERROR,fatal:!0,reason:"could not create source buffer for media codec(s)"});a.forEach((function(t){e.executeNext(t)}))}},e.createSourceBuffers=function(t){var e=this.sourceBuffer,r=this.mediaSource;if(!r)throw Error("createSourceBuffers called when mediaSource was null");var i=0;for(var a in t)if(!e[a]){var l=t[a];if(!l)throw Error("source buffer exists for track "+a+", however track does not");var u=l.levelCodec||l.codec,h=l.container+";codecs="+u;o.b.log("[buffer-controller]: creating sourceBuffer("+h+")");try{var d=e[a]=r.addSourceBuffer(h),c=a;this.addBufferListener(c,"updatestart",this._onSBUpdateStart),this.addBufferListener(c,"updateend",this._onSBUpdateEnd),this.addBufferListener(c,"error",this._onSBUpdateError),this.tracks[a]={buffer:d,codec:u,container:l.container,levelCodec:l.levelCodec,id:l.id},i++}catch(t){o.b.error("[buffer-controller]: error while trying to add sourceBuffer: "+t.message),this.hls.trigger(n.a.ERROR,{type:s.b.MEDIA_ERROR,details:s.a.BUFFER_ADD_CODEC_ERROR,fatal:!1,error:t,mimeType:h})}}i&&this.hls.trigger(n.a.BUFFER_CREATED,{tracks:this.tracks})},e._onSBUpdateStart=function(t){this.operationQueue.current(t).onStart()},e._onSBUpdateEnd=function(t){var e=this.operationQueue;e.current(t).onComplete(),e.shiftAndExecuteNext(t)},e._onSBUpdateError=function(t,e){o.b.error("[buffer-controller]: "+t+" SourceBuffer error",e),this.hls.trigger(n.a.ERROR,{type:s.b.MEDIA_ERROR,details:s.a.BUFFER_APPENDING_ERROR,fatal:!1});var r=this.operationQueue.current(t);r&&r.onError(e)},e.removeExecutor=function(t,e,r){var i=this.media,n=this.mediaSource,s=this.operationQueue,l=this.sourceBuffer[t];if(!i||!n||!l)return o.b.warn("[buffer-controller]: Attempting to remove from the "+t+" SourceBuffer, but it does not exist"),void s.shiftAndExecuteNext(t);var u=Object(a.a)(i.duration)?i.duration:1/0,h=Object(a.a)(n.duration)?n.duration:1/0,d=Math.max(0,e),c=Math.min(r,u,h);c>d?(o.b.log("[buffer-controller]: Removing ["+d+","+c+"] from the "+t+" SourceBuffer"),l.remove(d,c)):s.shiftAndExecuteNext(t)},e.appendExecutor=function(t,e){var r=this.operationQueue,i=this.sourceBuffer[e];if(!i)return o.b.warn("[buffer-controller]: Attempting to append to the "+e+" SourceBuffer, but it does not exist"),void r.shiftAndExecuteNext(e);i.ended=!1,i.appendBuffer(t)},e.blockBuffers=function(t,e){var r=this;if(void 0===e&&(e=this.getSourceBufferTypes()),!e.length)return o.b.log("[buffer-controller]: Blocking operation requested, but no SourceBuffers exist"),void Promise.resolve(t);var i=this.operationQueue,a=e.map((function(t){return i.appendBlocker(t)}));Promise.all(a).then((function(){t(),e.forEach((function(t){var e=r.sourceBuffer[t];e&&e.updating||i.shiftAndExecuteNext(t)}))}))},e.getSourceBufferTypes=function(){return Object.keys(this.sourceBuffer)},e.addBufferListener=function(t,e,r){var i=this.sourceBuffer[t];if(i){var a=r.bind(this,t);this.listeners[t].push({event:e,listener:a}),i.addEventListener(e,a)}},e.removeBufferListeners=function(t){var e=this.sourceBuffer[t];e&&this.listeners[t].forEach((function(t){e.removeEventListener(t.event,t.listener)}))},t}(),De={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,128:174,129:176,130:189,131:191,132:8482,133:162,134:163,135:9834,136:224,137:32,138:232,139:226,140:234,141:238,142:244,143:251,144:193,145:201,146:211,147:218,148:220,149:252,150:8216,151:161,152:42,153:8217,154:9473,155:169,156:8480,157:8226,158:8220,159:8221,160:192,161:194,162:199,163:200,164:202,165:203,166:235,167:206,168:207,169:239,170:212,171:217,172:249,173:219,174:171,175:187,176:195,177:227,178:205,179:204,180:236,181:210,182:242,183:213,184:245,185:123,186:125,187:92,188:94,189:95,190:124,191:8764,192:196,193:228,194:214,195:246,196:223,197:165,198:164,199:9475,200:197,201:229,202:216,203:248,204:9487,205:9491,206:9495,207:9499},ke=function(t){var e=t;return De.hasOwnProperty(t)&&(e=De[t]),String.fromCharCode(e)},_e={17:1,18:3,21:5,22:7,23:9,16:11,19:12,20:14},Ie={17:2,18:4,21:6,22:8,23:10,19:13,20:15},Ce={25:1,26:3,29:5,30:7,31:9,24:11,27:12,28:14},we={25:2,26:4,29:6,30:8,31:10,27:13,28:15},Oe=["white","green","blue","cyan","red","yellow","magenta","black","transparent"];!function(t){t[t.ERROR=0]="ERROR",t[t.TEXT=1]="TEXT",t[t.WARNING=2]="WARNING",t[t.INFO=2]="INFO",t[t.DEBUG=3]="DEBUG",t[t.DATA=3]="DATA"}(Ee||(Ee={}));var xe=function(){function t(){this.time=null,this.verboseLevel=Ee.ERROR}return t.prototype.log=function(t,e){this.verboseLevel>=t&&o.b.log(this.time+" ["+t+"] "+e)},t}(),Pe=function(t){for(var e=[],r=0;r100&&(this.logger.log(Ee.DEBUG,"Too large cursor position "+this.pos),this.pos=100)},e.moveCursor=function(t){var e=this.pos+t;if(t>1)for(var r=this.pos+1;r=144&&this.backSpace();var e=ke(t);this.pos>=100?this.logger.log(Ee.ERROR,"Cannot insert "+t.toString(16)+" ("+e+") at position "+this.pos+". Skipping it!"):(this.chars[this.pos].setChar(e,this.currPenState),this.moveCursor(1))},e.clearFromPos=function(t){var e;for(e=t;e<100;e++)this.chars[e].reset()},e.clear=function(){this.clearFromPos(0),this.pos=0,this.currPenState.reset()},e.clearToEndOfRow=function(){this.clearFromPos(this.pos)},e.getTextString=function(){for(var t=[],e=!0,r=0;r<100;r++){var i=this.chars[r].uchar;" "!==i&&(e=!1),t.push(i)}return e?"":t.join("")},e.setPenStyles=function(t){this.currPenState.setStyles(t),this.chars[this.pos].setPenState(this.currPenState)},t}(),Ue=function(){function t(t){this.rows=void 0,this.currRow=void 0,this.nrRollUpRows=void 0,this.lastOutputScreen=void 0,this.logger=void 0,this.rows=[];for(var e=0;e<15;e++)this.rows.push(new Ne(t));this.logger=t,this.currRow=14,this.nrRollUpRows=null,this.lastOutputScreen=null,this.reset()}var e=t.prototype;return e.reset=function(){for(var t=0;t<15;t++)this.rows[t].clear();this.currRow=14},e.equals=function(t){for(var e=!0,r=0;r<15;r++)if(!this.rows[r].equals(t.rows[r])){e=!1;break}return e},e.copy=function(t){for(var e=0;e<15;e++)this.rows[e].copy(t.rows[e])},e.isEmpty=function(){for(var t=!0,e=0;e<15;e++)if(!this.rows[e].isEmpty()){t=!1;break}return t},e.backSpace=function(){this.rows[this.currRow].backSpace()},e.clearToEndOfRow=function(){this.rows[this.currRow].clearToEndOfRow()},e.insertChar=function(t){this.rows[this.currRow].insertChar(t)},e.setPen=function(t){this.rows[this.currRow].setPenStyles(t)},e.moveCursor=function(t){this.rows[this.currRow].moveCursor(t)},e.setCursor=function(t){this.logger.log(Ee.INFO,"setCursor: "+t),this.rows[this.currRow].setCursor(t)},e.setPAC=function(t){this.logger.log(Ee.INFO,"pacData = "+JSON.stringify(t));var e=t.row-1;if(this.nrRollUpRows&&e0&&(r=t?"["+e.join(" | ")+"]":e.join("\n")),r},e.getTextAndFormat=function(){return this.rows},t}(),Be=function(){function t(t,e,r){this.chNr=void 0,this.outputFilter=void 0,this.mode=void 0,this.verbose=void 0,this.displayedMemory=void 0,this.nonDisplayedMemory=void 0,this.lastOutputScreen=void 0,this.currRollUpRow=void 0,this.writeScreen=void 0,this.cueStartTime=void 0,this.logger=void 0,this.chNr=t,this.outputFilter=e,this.mode=null,this.verbose=0,this.displayedMemory=new Ue(r),this.nonDisplayedMemory=new Ue(r),this.lastOutputScreen=new Ue(r),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null,this.logger=r}var e=t.prototype;return e.reset=function(){this.mode=null,this.displayedMemory.reset(),this.nonDisplayedMemory.reset(),this.lastOutputScreen.reset(),this.outputFilter.reset(),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null},e.getHandler=function(){return this.outputFilter},e.setHandler=function(t){this.outputFilter=t},e.setPAC=function(t){this.writeScreen.setPAC(t)},e.setBkgData=function(t){this.writeScreen.setBkgData(t)},e.setMode=function(t){t!==this.mode&&(this.mode=t,this.logger.log(Ee.INFO,"MODE="+t),"MODE_POP-ON"===this.mode?this.writeScreen=this.nonDisplayedMemory:(this.writeScreen=this.displayedMemory,this.writeScreen.reset()),"MODE_ROLL-UP"!==this.mode&&(this.displayedMemory.nrRollUpRows=null,this.nonDisplayedMemory.nrRollUpRows=null),this.mode=t)},e.insertChars=function(t){for(var e=0;e=46,e.italics)e.foreground="white";else{var r=Math.floor(t/2)-16;e.foreground=["white","green","blue","cyan","red","yellow","magenta"][r]}this.logger.log(Ee.INFO,"MIDROW: "+JSON.stringify(e)),this.writeScreen.setPen(e)},e.outputDataUpdate=function(t){void 0===t&&(t=!1);var e=this.logger.time;null!==e&&this.outputFilter&&(null!==this.cueStartTime||this.displayedMemory.isEmpty()?this.displayedMemory.equals(this.lastOutputScreen)||(this.outputFilter.newCue(this.cueStartTime,e,this.lastOutputScreen),t&&this.outputFilter.dispatchCue&&this.outputFilter.dispatchCue(),this.cueStartTime=this.displayedMemory.isEmpty()?null:e):this.cueStartTime=e,this.lastOutputScreen.copy(this.displayedMemory))},e.cueSplitAtTime=function(t){this.outputFilter&&(this.displayedMemory.isEmpty()||(this.outputFilter.newCue&&this.outputFilter.newCue(this.cueStartTime,t,this.displayedMemory),this.cueStartTime=t))},t}();function Ge(t,e,r){r.a=t,r.b=e}function Ke(t,e,r){return r.a===t&&r.b===e}var je=function(){function t(t,e,r){this.channels=void 0,this.currentChannel=0,this.cmdHistory=void 0,this.logger=void 0;var i=new xe;this.channels=[null,new Be(t,e,i),new Be(t+1,r,i)],this.cmdHistory={a:null,b:null},this.logger=i}var e=t.prototype;return e.getHandler=function(t){return this.channels[t].getHandler()},e.setHandler=function(t,e){this.channels[t].setHandler(e)},e.addData=function(t,e){var r,i,a,n=!1;this.logger.time=t;for(var s=0;s ("+Pe([i,a])+")"),(r=this.parseCmd(i,a))||(r=this.parseMidrow(i,a)),r||(r=this.parsePAC(i,a)),r||(r=this.parseBackgroundAttributes(i,a)),!r&&(n=this.parseChars(i,a))){var o=this.currentChannel;if(o&&o>0)this.channels[o].insertChars(n);else this.logger.log(Ee.WARNING,"No channel found yet. TEXT-MODE?")}r||n||this.logger.log(Ee.WARNING,"Couldn't parse cleaned data "+Pe([i,a])+" orig: "+Pe([e[s],e[s+1]]))}},e.parseCmd=function(t,e){var r=this.cmdHistory;if(!((20===t||28===t||21===t||29===t)&&e>=32&&e<=47)&&!((23===t||31===t)&&e>=33&&e<=35))return!1;if(Ke(t,e,r))return Ge(null,null,r),this.logger.log(Ee.DEBUG,"Repeated command ("+Pe([t,e])+") is dropped"),!0;var i=20===t||21===t||23===t?1:2,a=this.channels[i];return 20===t||21===t||28===t||29===t?32===e?a.ccRCL():33===e?a.ccBS():34===e?a.ccAOF():35===e?a.ccAON():36===e?a.ccDER():37===e?a.ccRU(2):38===e?a.ccRU(3):39===e?a.ccRU(4):40===e?a.ccFON():41===e?a.ccRDC():42===e?a.ccTR():43===e?a.ccRTD():44===e?a.ccEDM():45===e?a.ccCR():46===e?a.ccENM():47===e&&a.ccEOC():a.ccTO(e-32),Ge(t,e,r),this.currentChannel=i,!0},e.parseMidrow=function(t,e){var r=0;if((17===t||25===t)&&e>=32&&e<=47){if((r=17===t?1:2)!==this.currentChannel)return this.logger.log(Ee.ERROR,"Mismatch channel in midrow parsing"),!1;var i=this.channels[r];return!!i&&(i.ccMIDROW(e),this.logger.log(Ee.DEBUG,"MIDROW ("+Pe([t,e])+")"),!0)}return!1},e.parsePAC=function(t,e){var r,i=this.cmdHistory;if(!((t>=17&&t<=23||t>=25&&t<=31)&&e>=64&&e<=127)&&!((16===t||24===t)&&e>=64&&e<=95))return!1;if(Ke(t,e,i))return Ge(null,null,i),!0;var a=t<=23?1:2;r=e>=64&&e<=95?1===a?_e[t]:Ce[t]:1===a?Ie[t]:we[t];var n=this.channels[a];return!!n&&(n.setPAC(this.interpretPAC(r,e)),Ge(t,e,i),this.currentChannel=a,!0)},e.interpretPAC=function(t,e){var r,i={color:null,italics:!1,indent:null,underline:!1,row:t};return r=e>95?e-96:e-64,i.underline=1==(1&r),r<=13?i.color=["white","green","blue","cyan","red","yellow","magenta","white"][Math.floor(r/2)]:r<=15?(i.italics=!0,i.color="white"):i.indent=4*Math.floor((r-16)/2),i},e.parseChars=function(t,e){var r,i,a=null,n=null;(t>=25?(r=2,n=t-8):(r=1,n=t),n>=17&&n<=19)?(i=17===n?e+80:18===n?e+112:e+144,this.logger.log(Ee.INFO,"Special char '"+ke(i)+"' in channel "+r),a=[i]):t>=32&&t<=127&&(a=0===e?[t]:[t,e]);if(a){var s=Pe(a);this.logger.log(Ee.DEBUG,"Char codes = "+s.join(",")),Ge(t,e,this.cmdHistory)}return a},e.parseBackgroundAttributes=function(t,e){var r;if(!((16===t||24===t)&&e>=32&&e<=47)&&!((23===t||31===t)&&e>=45&&e<=47))return!1;var i={};16===t||24===t?(r=Math.floor((e-32)/2),i.background=Oe[r],e%2==1&&(i.background=i.background+"_semi")):45===e?i.background="transparent":(i.foreground="black",47===e&&(i.underline=!0));var a=t<=23?1:2;return this.channels[a].setBkgData(i),Ge(t,e,this.cmdHistory),!0},e.reset=function(){for(var t=0;tt)&&(this.startTime=t),this.endTime=e,this.screen=r,this.timelineController.createCaptionsTrack(this.trackName)},e.reset=function(){this.cueRanges=[]},t}(),Ve=function(){if("undefined"!=typeof self&&self.VTTCue)return self.VTTCue;var t=["","lr","rl"],e=["start","middle","end","left","right"];function r(t,e){if("string"!=typeof e)return!1;if(!Array.isArray(t))return!1;var r=e.toLowerCase();return!!~t.indexOf(r)&&r}function i(t){return r(e,t)}function a(t){for(var e=arguments.length,r=new Array(e>1?e-1:0),i=1;i100)throw new Error("Position must be between 0 and 100.");T=t,this.hasBeenReset=!0}})),Object.defineProperty(o,"positionAlign",a({},l,{get:function(){return E},set:function(t){var e=i(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");E=e,this.hasBeenReset=!0}})),Object.defineProperty(o,"size",a({},l,{get:function(){return b},set:function(t){if(t<0||t>100)throw new Error("Size must be between 0 and 100.");b=t,this.hasBeenReset=!0}})),Object.defineProperty(o,"align",a({},l,{get:function(){return S},set:function(t){var e=i(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");S=e,this.hasBeenReset=!0}})),o.displayState=void 0}return n.prototype.getCueAsHTML=function(){return self.WebVTT.convertCueToDOMTree(self,this.text)},n}(),We=function(){function t(){}return t.prototype.decode=function(t,e){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))},t}();function Ye(t){function e(t,e,r,i){return 3600*(0|t)+60*(0|e)+(0|r)+parseFloat(i||0)}var r=t.match(/^(?:(\d+):)?(\d{2}):(\d{2})(\.\d+)?/);return r?parseFloat(r[2])>59?e(r[2],r[3],0,r[4]):e(r[1],r[2],r[3],r[4]):null}var qe=function(){function t(){this.values=Object.create(null)}var e=t.prototype;return e.set=function(t,e){this.get(t)||""===e||(this.values[t]=e)},e.get=function(t,e,r){return r?this.has(t)?this.values[t]:e[r]:this.has(t)?this.values[t]:e},e.has=function(t){return t in this.values},e.alt=function(t,e,r){for(var i=0;i=0&&r<=100)return this.set(t,r),!0}return!1},t}();function Xe(t,e,r,i){var a=i?t.split(i):[t];for(var n in a)if("string"==typeof a[n]){var s=a[n].split(r);if(2===s.length)e(s[0],s[1])}}var ze=new Ve(0,0,""),Qe="middle"===ze.align?"middle":"center";function $e(t,e,r){var i=t;function a(){var e=Ye(t);if(null===e)throw new Error("Malformed timestamp: "+i);return t=t.replace(/^[^\sa-zA-Z-]+/,""),e}function n(){t=t.replace(/^\s+/,"")}if(n(),e.startTime=a(),n(),"--\x3e"!==t.substr(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+i);t=t.substr(3),n(),e.endTime=a(),n(),function(t,e){var i=new qe;Xe(t,(function(t,e){var a;switch(t){case"region":for(var n=r.length-1;n>=0;n--)if(r[n].id===e){i.set(t,r[n].region);break}break;case"vertical":i.alt(t,e,["rl","lr"]);break;case"line":a=e.split(","),i.integer(t,a[0]),i.percent(t,a[0])&&i.set("snapToLines",!1),i.alt(t,a[0],["auto"]),2===a.length&&i.alt("lineAlign",a[1],["start",Qe,"end"]);break;case"position":a=e.split(","),i.percent(t,a[0]),2===a.length&&i.alt("positionAlign",a[1],["start",Qe,"end","line-left","line-right","auto"]);break;case"size":i.percent(t,e);break;case"align":i.alt(t,e,["start",Qe,"end","left","right"])}}),/:/,/\s/),e.region=i.get("region",null),e.vertical=i.get("vertical","");var a=i.get("line","auto");"auto"===a&&-1===ze.line&&(a=-1),e.line=a,e.lineAlign=i.get("lineAlign","start"),e.snapToLines=i.get("snapToLines",!0),e.size=i.get("size",100),e.align=i.get("align",Qe);var n=i.get("position","auto");"auto"===n&&50===ze.position&&(n="start"===e.align||"left"===e.align?0:"end"===e.align||"right"===e.align?100:50),e.position=n}(t,e)}function Je(t){return t.replace(//gi,"\n")}var Ze=function(){function t(){this.state="INITIAL",this.buffer="",this.decoder=new We,this.regionList=[],this.cue=null,this.oncue=void 0,this.onparsingerror=void 0,this.onflush=void 0}var e=t.prototype;return e.parse=function(t){var e=this;function r(){var t=e.buffer,r=0;for(t=Je(t);r>>0).toString()};function nr(t,e,r){return ar(t.toString())+ar(e.toString())+ar(r)}function sr(t,e,r,i,n,s,o,l){var u,h=new Ze,d=Object(F.f)(new Uint8Array(t)).trim().replace(rr,"\n").split("\n"),c=[],f=Object(tr.a)(e,r),g="00:00.000",v=0,p=0,m=!0,y=!1;h.oncue=function(t){var e=i[n],r=i.ccOffset,a=(v-f)/9e4;if(null!=e&&e.new&&(void 0!==p?r=i.ccOffset=e.start:function(t,e,r){var i=t[e],a=t[i.prevCC];if(!a||!a.new&&i.new)return t.ccOffset=t.presentationOffset=i.start,void(i.new=!1);for(;null!==(n=a)&&void 0!==n&&n.new;){var n;t.ccOffset+=i.start-a.start,i.new=!1,a=t[(i=a).prevCC]}t.presentationOffset=r}(i,n,a)),a&&(r=a-i.presentationOffset),y){var o=t.endTime-t.startTime,l=Object(er.b)(9e4*(t.startTime+r-p),9e4*s)/9e4;t.startTime=l,t.endTime=l+o}var u=t.text.trim();t.text=decodeURIComponent(encodeURIComponent(u)),t.id||(t.id=nr(t.startTime,t.endTime,u)),t.endTime>0&&c.push(t)},h.onparsingerror=function(t){u=t},h.onflush=function(){u?l(u):o(c)},d.forEach((function(t){if(m){if(ir(t,"X-TIMESTAMP-MAP=")){m=!1,y=!0,t.substr(16).split(",").forEach((function(t){ir(t,"LOCAL:")?g=t.substr(6):ir(t,"MPEGTS:")&&(v=parseInt(t.substr(7)))}));try{p=function(t){var e=parseInt(t.substr(-3)),r=parseInt(t.substr(-6,2)),i=parseInt(t.substr(-9,2)),n=t.length>9?parseInt(t.substr(0,t.indexOf(":"))):0;if(!(Object(a.a)(e)&&Object(a.a)(r)&&Object(a.a)(i)&&Object(a.a)(n)))throw Error("Malformed X-TIMESTAMP-MAP: Local:"+t);return e+=1e3*r,e+=6e4*i,e+=36e5*n}(g)/1e3}catch(t){y=!1,u=t}return}""===t&&(m=!1)}h.parse(t+"\n")})),h.flush()}function or(){return(or=Object.assign||function(t){for(var e=1;e=0&&(c[0]=Math.min(c[0],e),c[1]=Math.max(c[1],r),h=!0,f/(r-e)>.5))return}if(h||a.push([e,r]),this.config.renderTextTracksNatively){var g=this.captionsTracks[t];this.Cues.newCue(g,e,r,i)}else{var v=this.Cues.newCue(null,e,r,i);this.hls.trigger(n.a.CUES_PARSED,{type:"captions",cues:v,track:t})}},e.onInitPtsFound=function(t,e){var r=this,i=e.frag,a=e.id,s=e.initPTS,o=e.timescale,l=this.unparsedVttFrags;"main"===a&&(this.initPTS[i.cc]=s,this.timescale[i.cc]=o),l.length&&(this.unparsedVttFrags=[],l.forEach((function(t){r.onFragLoaded(n.a.FRAG_LOADED,t)})))},e.getExistingTrack=function(t){var e=this.media;if(e)for(var r=0;r0&&this.mediaWidth>0){var t=this.hls.levels;if(t.length){var e=this.hls;e.autoLevelCapping=this.getMaxLevel(t.length-1),e.autoLevelCapping>this.autoLevelCapping&&this.streamController&&this.streamController.nextLevelSwitch(),this.autoLevelCapping=e.autoLevelCapping}}},a.getMaxLevel=function(e){var r=this,i=this.hls.levels;if(!i.length)return-1;var a=i.filter((function(i,a){return t.isLevelAllowed(a,r.restrictedLevels)&&a<=e}));return this.clientRect=null,t.getMaxLevelByMediaSize(a,this.mediaWidth,this.mediaHeight)},a.startCapping=function(){this.timer||(this.autoLevelCapping=Number.POSITIVE_INFINITY,this.hls.firstLevel=this.getMaxLevel(this.firstLevel),self.clearInterval(this.timer),this.timer=self.setInterval(this.detectPlayerSize.bind(this),1e3),this.detectPlayerSize())},a.stopCapping=function(){this.restrictedLevels=[],this.firstLevel=-1,this.autoLevelCapping=Number.POSITIVE_INFINITY,this.timer&&(self.clearInterval(this.timer),this.timer=void 0)},a.getDimensions=function(){if(this.clientRect)return this.clientRect;var t=this.media,e={width:0,height:0};if(t){var r=t.getBoundingClientRect();e.width=r.width,e.height=r.height,e.width||e.height||(e.width=r.right-r.left||t.width||0,e.height=r.bottom-r.top||t.height||0)}return this.clientRect=e,e},t.isLevelAllowed=function(t,e){return void 0===e&&(e=[]),-1===e.indexOf(t)},t.getMaxLevelByMediaSize=function(t,e,r){if(!t||!t.length)return-1;for(var i,a,n=t.length-1,s=0;s=e||o.height>=r)&&(i=o,!(a=t[s+1])||i.width!==a.width||i.height!==a.height)){n=s;break}}return n},e=t,i=[{key:"contentScaleFactor",get:function(){var t=1;try{t=self.devicePixelRatio}catch(t){}return t}}],(r=[{key:"mediaWidth",get:function(){return this.getDimensions().width*t.contentScaleFactor}},{key:"mediaHeight",get:function(){return this.getDimensions().height*t.contentScaleFactor}}])&&Tr(e.prototype,r),i&&Tr(e,i),t}(),Sr=function(){function t(t){this.hls=void 0,this.isVideoPlaybackQualityAvailable=!1,this.timer=void 0,this.media=null,this.lastTime=void 0,this.lastDroppedFrames=0,this.lastDecodedFrames=0,this.streamController=void 0,this.hls=t,this.registerListeners()}var e=t.prototype;return e.setStreamController=function(t){this.streamController=t},e.registerListeners=function(){this.hls.on(n.a.MEDIA_ATTACHING,this.onMediaAttaching,this)},e.unregisterListeners=function(){this.hls.off(n.a.MEDIA_ATTACHING,this.onMediaAttaching)},e.destroy=function(){this.timer&&clearInterval(this.timer),this.unregisterListeners(),this.isVideoPlaybackQualityAvailable=!1,this.media=null},e.onMediaAttaching=function(t,e){var r=this.hls.config;if(r.capLevelOnFPSDrop){var i=e.media instanceof self.HTMLVideoElement?e.media:null;this.media=i,i&&"function"==typeof i.getVideoPlaybackQuality&&(this.isVideoPlaybackQualityAvailable=!0),self.clearInterval(this.timer),this.timer=self.setTimeout(this.checkFPSInterval.bind(this),r.fpsDroppedMonitoringPeriod)}},e.checkFPS=function(t,e,r){var i=performance.now();if(e){if(this.lastTime){var a=i-this.lastTime,s=r-this.lastDroppedFrames,l=e-this.lastDecodedFrames,u=1e3*s/a,h=this.hls;if(h.trigger(n.a.FPS_DROP,{currentDropped:s,currentDecoded:l,totalDroppedFrames:r}),u>0&&s>h.config.fpsDroppedMonitoringThreshold*l){var d=h.currentLevel;o.b.warn("drop FPS ratio greater than max allowed value for currentLevel: "+d),d>0&&(-1===h.autoLevelCapping||h.autoLevelCapping>=d)&&(d-=1,h.trigger(n.a.FPS_DROP_LEVEL_CAPPING,{level:d,droppedLevel:h.currentLevel}),h.autoLevelCapping=d,this.streamController.nextLevelSwitch())}}this.lastTime=i,this.lastDroppedFrames=r,this.lastDecodedFrames=e}},e.checkFPSInterval=function(){var t=this.media;if(t)if(this.isVideoPlaybackQualityAvailable){var e=t.getVideoPlaybackQuality();this.checkFPS(t,e.totalVideoFrames,e.droppedVideoFrames)}else this.checkFPS(t,t.webkitDecodedFrameCount,t.webkitDroppedFrameCount)},t}();!function(t){t.WIDEVINE="com.widevine.alpha",t.PLAYREADY="com.microsoft.playready"}(Er||(Er={}));var Lr="undefined"!=typeof self&&self.navigator&&self.navigator.requestMediaKeySystemAccess?self.navigator.requestMediaKeySystemAccess.bind(self.navigator):null;function Ar(t,e){for(var r=0;r3)return void this.hls.trigger(n.a.ERROR,{type:s.b.KEY_SYSTEM_ERROR,details:s.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0});var u=3-this._requestLicenseFailureCount+1;o.b.warn("Retrying license request, "+u+" attempts left"),this._requestLicense(r,i)}}},a._generateLicenseRequestChallenge=function(t,e){switch(t.mediaKeySystemDomain){case Er.WIDEVINE:return e}throw new Error("unsupported key-system: "+t.mediaKeySystemDomain)},a._requestLicense=function(t,e){o.b.log("Requesting content license for key-system");var r=this._mediaKeysList[0];if(!r)return o.b.error("Fatal error: Media is encrypted but no key-system access has been obtained yet"),void this.hls.trigger(n.a.ERROR,{type:s.b.KEY_SYSTEM_ERROR,details:s.a.KEY_SYSTEM_NO_ACCESS,fatal:!0});try{var i=this.getLicenseServerUrl(r.mediaKeySystemDomain),a=this._createLicenseXhr(i,t,e);o.b.log("Sending license request to URL: "+i);var l=this._generateLicenseRequestChallenge(r,t);a.send(l)}catch(t){o.b.error("Failure requesting DRM license: "+t),this.hls.trigger(n.a.ERROR,{type:s.b.KEY_SYSTEM_ERROR,details:s.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0})}},a.onMediaAttached=function(t,e){if(this._emeEnabled){var r=e.media;this._media=r,r.addEventListener("encrypted",this._onMediaEncrypted)}},a.onMediaDetached=function(){var t=this._media,e=this._mediaKeysList;t&&(t.removeEventListener("encrypted",this._onMediaEncrypted),this._media=null,this._mediaKeysList=[],Promise.all(e.map((function(t){if(t.mediaKeysSession)return t.mediaKeysSession.close().catch((function(){}))}))).then((function(){return t.setMediaKeys(null)})).catch((function(){})))},a.onManifestParsed=function(t,e){if(this._emeEnabled){var r=e.levels.map((function(t){return t.audioCodec})).filter((function(t){return!!t})),i=e.levels.map((function(t){return t.videoCodec})).filter((function(t){return!!t}));this._attemptKeySystemAccess(Er.WIDEVINE,r,i)}},e=t,(r=[{key:"requestMediaKeySystemAccess",get:function(){if(!this._requestMediaKeySystemAccess)throw new Error("No requestMediaKeySystemAccess function configured");return this._requestMediaKeySystemAccess}}])&&Ar(e.prototype,r),i&&Ar(e,i),t}(),Dr=r(11),kr=/^age:\s*[\d.]+\s*$/m,_r=function(){function t(t){this.xhrSetup=void 0,this.requestTimeout=void 0,this.retryTimeout=void 0,this.retryDelay=void 0,this.config=null,this.callbacks=null,this.context=void 0,this.loader=null,this.stats=void 0,this.xhrSetup=t?t.xhrSetup:null,this.stats=new Dr.a,this.retryDelay=0}var e=t.prototype;return e.destroy=function(){this.callbacks=null,this.abortInternal(),this.loader=null,this.config=null},e.abortInternal=function(){var t=this.loader;self.clearTimeout(this.requestTimeout),self.clearTimeout(this.retryTimeout),t&&(t.onreadystatechange=null,t.onprogress=null,4!==t.readyState&&(this.stats.aborted=!0,t.abort()))},e.abort=function(){var t;this.abortInternal(),null!==(t=this.callbacks)&&void 0!==t&&t.onAbort&&this.callbacks.onAbort(this.stats,this.context,this.loader)},e.load=function(t,e,r){if(this.stats.loading.start)throw new Error("Loader can only be used once.");this.stats.loading.start=self.performance.now(),this.context=t,this.config=e,this.callbacks=r,this.retryDelay=e.retryDelay,this.loadInternal()},e.loadInternal=function(){var t=this.config,e=this.context;if(t){var r=this.loader=new self.XMLHttpRequest,i=this.stats;i.loading.first=0,i.loaded=0;var a=this.xhrSetup;try{if(a)try{a(r,e.url)}catch(t){r.open("GET",e.url,!0),a(r,e.url)}r.readyState||r.open("GET",e.url,!0)}catch(t){return void this.callbacks.onError({code:r.status,text:t.message},e,r)}e.rangeEnd&&r.setRequestHeader("Range","bytes="+e.rangeStart+"-"+(e.rangeEnd-1)),r.onreadystatechange=this.readystatechange.bind(this),r.onprogress=this.loadprogress.bind(this),r.responseType=e.responseType,self.clearTimeout(this.requestTimeout),this.requestTimeout=self.setTimeout(this.loadtimeout.bind(this),t.timeout),r.send()}},e.readystatechange=function(){var t=this.context,e=this.loader,r=this.stats;if(t&&e){var i=e.readyState,a=this.config;if(!r.aborted&&i>=2)if(self.clearTimeout(this.requestTimeout),0===r.loading.first&&(r.loading.first=Math.max(self.performance.now(),r.loading.start)),4===i){e.onreadystatechange=null,e.onprogress=null;var n=e.status;if(n>=200&&n<300){var s,l;if(r.loading.end=Math.max(self.performance.now(),r.loading.first),l="arraybuffer"===t.responseType?(s=e.response).byteLength:(s=e.responseText).length,r.loaded=r.total=l,!this.callbacks)return;var u=this.callbacks.onProgress;if(u&&u(r,t,s,e),!this.callbacks)return;var h={url:e.responseURL,data:s};this.callbacks.onSuccess(h,r,t,e)}else r.retry>=a.maxRetry||n>=400&&n<499?(o.b.error(n+" while loading "+t.url),this.callbacks.onError({code:n,text:e.statusText},t,e)):(o.b.warn(n+" while loading "+t.url+", retrying in "+this.retryDelay+"..."),this.abortInternal(),this.loader=null,self.clearTimeout(this.retryTimeout),this.retryTimeout=self.setTimeout(this.loadInternal.bind(this),this.retryDelay),this.retryDelay=Math.min(2*this.retryDelay,a.maxRetryDelay),r.retry++)}else self.clearTimeout(this.requestTimeout),this.requestTimeout=self.setTimeout(this.loadtimeout.bind(this),a.timeout)}},e.loadtimeout=function(){o.b.warn("timeout while loading "+this.context.url);var t=this.callbacks;t&&(this.abortInternal(),t.onTimeout(this.stats,this.context,this.loader))},e.loadprogress=function(t){var e=this.stats;e.loaded=t.loaded,t.lengthComputable&&(e.total=t.total)},e.getCacheAge=function(){var t=null;if(this.loader&&kr.test(this.loader.getAllResponseHeaders())){var e=this.loader.getResponseHeader("age");t=e?parseFloat(e):null}return t},t}();function Ir(t){var e="function"==typeof Map?new Map:void 0;return(Ir=function(t){if(null===t||(r=t,-1===Function.toString.call(r).indexOf("[native code]")))return t;var r;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return Cr(t,arguments,xr(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),Or(i,t)})(t)}function Cr(t,e,r){return(Cr=wr()?Reflect.construct:function(t,e,r){var i=[null];i.push.apply(i,e);var a=new(Function.bind.apply(t,i));return r&&Or(a,r.prototype),a}).apply(null,arguments)}function wr(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function Or(t,e){return(Or=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function xr(t){return(xr=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}var Pr=function(){function t(t){this.fetchSetup=void 0,this.requestTimeout=void 0,this.request=void 0,this.response=void 0,this.controller=void 0,this.context=void 0,this.config=null,this.callbacks=null,this.stats=void 0,this.loader=null,this.fetchSetup=t.fetchSetup||Mr,this.controller=new self.AbortController,this.stats=new Dr.a}var e=t.prototype;return e.destroy=function(){this.loader=this.callbacks=null,this.abortInternal()},e.abortInternal=function(){this.stats.aborted=!0,this.controller.abort()},e.abort=function(){var t;this.abortInternal(),null!==(t=this.callbacks)&&void 0!==t&&t.onAbort&&this.callbacks.onAbort(this.stats,this.context,this.response)},e.load=function(t,e,r){var i=this,n=this.stats;if(n.loading.start)throw new Error("Loader can only be used once.");n.loading.start=self.performance.now();var s=function(t,e){var r={method:"GET",mode:"cors",credentials:"same-origin",signal:e};t.rangeEnd&&(r.headers=new self.Headers({Range:"bytes="+t.rangeStart+"-"+String(t.rangeEnd-1)}));return r}(t,this.controller.signal),o=r.onProgress,l="arraybuffer"===t.responseType,u=l?"byteLength":"length";this.context=t,this.config=e,this.callbacks=r,this.request=this.fetchSetup(t,s),self.clearTimeout(this.requestTimeout),this.requestTimeout=self.setTimeout((function(){i.abortInternal(),r.onTimeout(n,t,i.response)}),e.timeout),self.fetch(this.request).then((function(r){if(i.response=i.loader=r,!r.ok){var s=r.status,u=r.statusText;throw new Fr(u||"fetch, bad network response",s,r)}return n.loading.first=Math.max(self.performance.now(),n.loading.start),n.total=parseInt(r.headers.get("Content-Length")||"0"),o&&Object(a.a)(e.highWaterMark)?i.loadProgressively(r,n,t,e.highWaterMark,o):l?r.arrayBuffer():r.text()})).then((function(s){var l=i.response;self.clearTimeout(i.requestTimeout),n.loading.end=Math.max(self.performance.now(),n.loading.first),n.loaded=n.total=s[u];var h={url:l.url,data:s};o&&!Object(a.a)(e.highWaterMark)&&o(n,t,s,l),r.onSuccess(h,n,t,l)})).catch((function(e){if(self.clearTimeout(i.requestTimeout),!n.aborted){var a=e.code||0;r.onError({code:a,text:e.message},t,e.details)}}))},e.getCacheAge=function(){var t=null;if(this.response){var e=this.response.headers.get("age");t=e?parseFloat(e):null}return t},e.loadProgressively=function(t,e,r,i,a){void 0===i&&(i=0);var n=new oe.a,s=t.body.getReader();return function o(){return s.read().then((function(s){if(s.done)return n.dataLength&&a(e,r,n.flush(),t),Promise.resolve(new ArrayBuffer(0));var l=s.value,u=l.length;return e.loaded+=u,u=i&&a(e,r,n.flush(),t)):a(e,r,l,t),o()})).catch((function(){return Promise.reject()}))}()},t}();function Mr(t,e){return new self.Request(t.url,e)}var Fr=function(t){var e,r;function i(e,r,i){var a;return(a=t.call(this,e)||this).code=void 0,a.details=void 0,a.code=r,a.details=i,a}return r=t,(e=i).prototype=Object.create(r.prototype),e.prototype.constructor=e,Or(e,r),i}(Ir(Error)),Nr=Pr,Ur=/\s/;function Br(){return(Br=Object.assign||function(t){for(var e=1;e=16?o--:o++;var f=Je(l.trim()),g=nr(e,r,f);t&&t.cues&&t.cues.getCueById(g)||((n=new h(e,r,f)).id=g,n.line=d+1,n.align="left",n.position=10+Math.min(80,10*Math.floor(8*o/32)),u.push(n))}return t&&u.length&&(u.sort((function(t,e){return"auto"===t.line||"auto"===e.line?0:t.line>8&&e.line>8?e.line-t.line:t.line-e.line})),u.forEach((function(e){return x(t,e)}))),u}},enableCEA708Captions:!0,enableWebVTT:!0,enableIMSC1:!0,captionsTextTrack1Label:"English",captionsTextTrack1LanguageCode:"en",captionsTextTrack2Label:"Spanish",captionsTextTrack2LanguageCode:"es",captionsTextTrack3Label:"Unknown CC",captionsTextTrack3LanguageCode:"",captionsTextTrack4Label:"Unknown CC",captionsTextTrack4LanguageCode:"",renderTextTracksNatively:!0}),{},{subtitleStreamController:pe,subtitleTrackController:be,timelineController:mr,audioStreamController:he,audioTrackController:fe,emeController:Rr});function Vr(t){var e=t.loader;e!==Nr&&e!==_r?(o.b.log("[config]: Custom loader detected, cannot enable progressive streaming"),t.progressive=!1):function(){if(self.fetch&&self.AbortController&&self.ReadableStream&&self.Request)try{return new self.ReadableStream({}),!0}catch(t){}return!1}()&&(t.loader=Nr,t.progressive=!0,t.enableSoftwareAES=!0,o.b.log("[config]: Progressive streaming enabled, using FetchLoader"))}function Wr(t,e){for(var r=0;re)return i;return 0}},{key:"maxAutoLevel",get:function(){var t=this.levels,e=this.autoLevelCapping;return-1===e&&t&&t.length?t.length-1:e}},{key:"nextAutoLevel",get:function(){return Math.min(Math.max(this.abrController.nextAutoLevel,this.minAutoLevel),this.maxAutoLevel)},set:function(t){this.abrController.nextAutoLevel=Math.max(this.minAutoLevel,t)}},{key:"audioTracks",get:function(){var t=this.audioTrackController;return t?t.audioTracks:[]}},{key:"audioTrack",get:function(){var t=this.audioTrackController;return t?t.audioTrack:-1},set:function(t){var e=this.audioTrackController;e&&(e.audioTrack=t)}},{key:"subtitleTracks",get:function(){var t=this.subtitleTrackController;return t?t.subtitleTracks:[]}},{key:"subtitleTrack",get:function(){var t=this.subtitleTrackController;return t?t.subtitleTrack:-1},set:function(t){var e=this.subtitleTrackController;e&&(e.subtitleTrack=t)}},{key:"media",get:function(){return this._media}},{key:"subtitleDisplay",get:function(){var t=this.subtitleTrackController;return!!t&&t.subtitleDisplay},set:function(t){var e=this.subtitleTrackController;e&&(e.subtitleDisplay=t)}},{key:"lowLatencyMode",get:function(){return this.config.lowLatencyMode},set:function(t){this.config.lowLatencyMode=t}},{key:"liveSyncPosition",get:function(){return this.latencyController.liveSyncPosition}},{key:"latency",get:function(){return this.latencyController.latency}},{key:"maxLatency",get:function(){return this.latencyController.maxLatency}},{key:"targetLatency",get:function(){return this.latencyController.targetLatency}},{key:"drift",get:function(){return this.latencyController.drift}},{key:"forceStartLoad",get:function(){return this.streamController.forceStartLoad}}])&&Wr(e.prototype,r),a&&Wr(e,a),t}();Yr.defaultConfig=void 0}]).default})); +// @source https://github.com/video-dev/hls.js/tree/v1.2.4 +"undefined"!=typeof window&&function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Hls=e():t.Hls=e()}(this,(function(){return function(t){var e={};function i(r){if(e[r])return e[r].exports;var n=e[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=t,i.c=e,i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)i.d(r,n,function(e){return t[e]}.bind(null,n));return r},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="/dist/",i(i.s=20)}([function(t,e,i){"use strict";var r;i.d(e,"a",(function(){return r})),function(t){t.MEDIA_ATTACHING="hlsMediaAttaching",t.MEDIA_ATTACHED="hlsMediaAttached",t.MEDIA_DETACHING="hlsMediaDetaching",t.MEDIA_DETACHED="hlsMediaDetached",t.BUFFER_RESET="hlsBufferReset",t.BUFFER_CODECS="hlsBufferCodecs",t.BUFFER_CREATED="hlsBufferCreated",t.BUFFER_APPENDING="hlsBufferAppending",t.BUFFER_APPENDED="hlsBufferAppended",t.BUFFER_EOS="hlsBufferEos",t.BUFFER_FLUSHING="hlsBufferFlushing",t.BUFFER_FLUSHED="hlsBufferFlushed",t.MANIFEST_LOADING="hlsManifestLoading",t.MANIFEST_LOADED="hlsManifestLoaded",t.MANIFEST_PARSED="hlsManifestParsed",t.LEVEL_SWITCHING="hlsLevelSwitching",t.LEVEL_SWITCHED="hlsLevelSwitched",t.LEVEL_LOADING="hlsLevelLoading",t.LEVEL_LOADED="hlsLevelLoaded",t.LEVEL_UPDATED="hlsLevelUpdated",t.LEVEL_PTS_UPDATED="hlsLevelPtsUpdated",t.LEVELS_UPDATED="hlsLevelsUpdated",t.AUDIO_TRACKS_UPDATED="hlsAudioTracksUpdated",t.AUDIO_TRACK_SWITCHING="hlsAudioTrackSwitching",t.AUDIO_TRACK_SWITCHED="hlsAudioTrackSwitched",t.AUDIO_TRACK_LOADING="hlsAudioTrackLoading",t.AUDIO_TRACK_LOADED="hlsAudioTrackLoaded",t.SUBTITLE_TRACKS_UPDATED="hlsSubtitleTracksUpdated",t.SUBTITLE_TRACKS_CLEARED="hlsSubtitleTracksCleared",t.SUBTITLE_TRACK_SWITCH="hlsSubtitleTrackSwitch",t.SUBTITLE_TRACK_LOADING="hlsSubtitleTrackLoading",t.SUBTITLE_TRACK_LOADED="hlsSubtitleTrackLoaded",t.SUBTITLE_FRAG_PROCESSED="hlsSubtitleFragProcessed",t.CUES_PARSED="hlsCuesParsed",t.NON_NATIVE_TEXT_TRACKS_FOUND="hlsNonNativeTextTracksFound",t.INIT_PTS_FOUND="hlsInitPtsFound",t.FRAG_LOADING="hlsFragLoading",t.FRAG_LOAD_EMERGENCY_ABORTED="hlsFragLoadEmergencyAborted",t.FRAG_LOADED="hlsFragLoaded",t.FRAG_DECRYPTED="hlsFragDecrypted",t.FRAG_PARSING_INIT_SEGMENT="hlsFragParsingInitSegment",t.FRAG_PARSING_USERDATA="hlsFragParsingUserdata",t.FRAG_PARSING_METADATA="hlsFragParsingMetadata",t.FRAG_PARSED="hlsFragParsed",t.FRAG_BUFFERED="hlsFragBuffered",t.FRAG_CHANGED="hlsFragChanged",t.FPS_DROP="hlsFpsDrop",t.FPS_DROP_LEVEL_CAPPING="hlsFpsDropLevelCapping",t.ERROR="hlsError",t.DESTROYING="hlsDestroying",t.KEY_LOADING="hlsKeyLoading",t.KEY_LOADED="hlsKeyLoaded",t.LIVE_BACK_BUFFER_REACHED="hlsLiveBackBufferReached",t.BACK_BUFFER_REACHED="hlsBackBufferReached"}(r||(r={}))},function(t,e,i){"use strict";i.d(e,"a",(function(){return o})),i.d(e,"b",(function(){return l}));var r=function(){},n={trace:r,debug:r,log:r,warn:r,info:r,error:r},a=n;function s(t){var e=self.console[t];return e?e.bind(self.console,"["+t+"] >"):r}function o(t){if(self.console&&!0===t||"object"==typeof t){!function(t){for(var e=arguments.length,i=new Array(e>1?e-1:0),r=1;r>24,t[e+1]=i>>16&255,t[e+2]=i>>8&255,t[e+3]=255&i}function g(t,e){var i=[];if(!e.length)return i;for(var r=t.byteLength,n=0;n1?n+a:r;if(u(t.subarray(n+4,n+8))===e[0])if(1===e.length)i.push(t.subarray(n+8,s));else{var l=g(t.subarray(n+8,s),e.slice(1));l.length&&o.apply(i,l)}n=s}return i}function v(t){var e=[],i=t[0],r=8,n=d(t,r);r+=4;r+=0===i?8:16,r+=2;var a=t.length+0,s=h(t,r);r+=2;for(var o=0;o>>31)return console.warn("SIDX has hierarchical references (not supported)"),null;var f=d(t,l);l+=4,e.push({referenceSize:c,subsegmentDuration:f,info:{duration:f/n,start:a,end:a+c-1}}),a+=c,r=l+=4}return{earliestPresentationTime:0,timescale:n,version:i,referencesCount:s,references:e}}function p(t){for(var e=[],i=g(t,["moov","trak"]),r=0;r=r.length)break;s+=u=r[n++]}while(255===u);o=0;do{if(n>=r.length)break;o+=u=r[n++]}while(255===u);var c=r.length-n;if(!l&&4===s&&n16){for(var E=[],S=0;S<16;S++){var L=r[n++].toString(16);E.push(1==L.length?"0"+L:L),3!==S&&5!==S&&7!==S&&9!==S||E.push("-")}for(var A=o-16,D=new Uint8Array(A),R=0;Rc)break}}function R(t){var e=t[0],i="",r="",n=0,a=0,s=0,o=0,l=0,h=0;if(0===e){for(;"\0"!==u(t.subarray(h,h+1));)i+=u(t.subarray(h,h+1)),h+=1;for(i+=u(t.subarray(h,h+1)),h+=1;"\0"!==u(t.subarray(h,h+1));)r+=u(t.subarray(h,h+1)),h+=1;r+=u(t.subarray(h,h+1)),h+=1,n=d(t,12),a=d(t,16),o=d(t,20),l=d(t,24),h=28}else if(1===e){n=d(t,h+=4);var c=d(t,h+=4),f=d(t,h+=4);for(h+=4,s=Math.pow(2,32)*c+f,Number.isSafeInteger(s)||(s=Number.MAX_SAFE_INTEGER,console.warn("Presentation time exceeds safe integer limit and wrapped to max safe integer in parsing emsg box")),o=d(t,h),l=d(t,h+=4),h+=4;"\0"!==u(t.subarray(h,h+1));)i+=u(t.subarray(h,h+1)),h+=1;for(i+=u(t.subarray(h,h+1)),h+=1;"\0"!==u(t.subarray(h,h+1));)r+=u(t.subarray(h,h+1)),h+=1;r+=u(t.subarray(h,h+1)),h+=1}return{schemeIdUri:i,value:r,timeScale:n,presentationTime:s,presentationTimeDelta:a,eventDuration:o,id:l,payload:t.subarray(h,t.byteLength)}}},function(t,e,i){"use strict";i.d(e,"a",(function(){return r})),i.d(e,"b",(function(){return g})),i.d(e,"c",(function(){return v}));var r,n=i(3),a=i(12),s=i(1),o=i(17),l=i(14);function u(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,h(t,e)}function h(t,e){return(h=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}function d(t,e){for(var i=0;i>8*(15-i)&255;return e},i.setDecryptDataFromLevelKey=function(t,e){var i=t;return"AES-128"===(null==t?void 0:t.method)&&t.uri&&!t.iv&&((i=o.a.fromURI(t.uri)).method=t.method,i.iv=this.createInitializationVector(e),i.keyFormat="identity"),i},i.setElementaryStreamInfo=function(t,e,i,r,n,a){void 0===a&&(a=!1);var s=this.elementaryStreams,o=s[t];o?(o.startPTS=Math.min(o.startPTS,e),o.endPTS=Math.max(o.endPTS,i),o.startDTS=Math.min(o.startDTS,r),o.endDTS=Math.max(o.endDTS,n)):s[t]={startPTS:e,endPTS:i,startDTS:r,endDTS:n,partial:a}},i.clearElementaryStreamInfo=function(){var t=this.elementaryStreams;t[r.AUDIO]=null,t[r.VIDEO]=null,t[r.AUDIOVIDEO]=null},c(e,[{key:"decryptdata",get:function(){if(!this.levelkey&&!this._decryptdata)return null;if(!this._decryptdata&&this.levelkey){var t=this.sn;"number"!=typeof t&&(this.levelkey&&"AES-128"===this.levelkey.method&&!this.levelkey.iv&&s.b.warn('missing IV for initialization segment with method="'+this.levelkey.method+'" - compliance issue'),t=0),this._decryptdata=this.setDecryptDataFromLevelKey(this.levelkey,t)}return this._decryptdata}},{key:"end",get:function(){return this.start+this.duration}},{key:"endProgramDateTime",get:function(){if(null===this.programDateTime)return null;if(!Object(n.a)(this.programDateTime))return null;var t=Object(n.a)(this.duration)?this.duration:0;return this.programDateTime+1e3*t}},{key:"encrypted",get:function(){var t;return!(null===(t=this.decryptdata)||void 0===t||!t.keyFormat||!this.decryptdata.uri)}}]),e}(f),v=function(t){function e(e,i,r,n,a){var s;(s=t.call(this,r)||this).fragOffset=0,s.duration=0,s.gap=!1,s.independent=!1,s.relurl=void 0,s.fragment=void 0,s.index=void 0,s.stats=new l.a,s.duration=e.decimalFloatingPoint("DURATION"),s.gap=e.bool("GAP"),s.independent=e.bool("INDEPENDENT"),s.relurl=e.enumeratedString("URI"),s.fragment=i,s.index=n;var o=e.enumeratedString("BYTERANGE");return o&&s.setByteRange(o,a),a&&(s.fragOffset=a.fragOffset+a.duration),s}return u(e,t),c(e,[{key:"start",get:function(){return this.fragment.start+this.fragOffset}},{key:"end",get:function(){return this.start+this.duration}},{key:"loaded",get:function(){var t=this.elementaryStreams;return!!(t.audio||t.video||t.audiovideo)}}]),e}(f)},function(t,e,i){"use strict";i.d(e,"b",(function(){return s})),i.d(e,"a",(function(){return l})),i.d(e,"d",(function(){return u})),i.d(e,"e",(function(){return h})),i.d(e,"c",(function(){return c})),i.d(e,"f",(function(){return y}));var r,n=function(t,e){return e+10<=t.length&&73===t[e]&&68===t[e+1]&&51===t[e+2]&&t[e+3]<255&&t[e+4]<255&&t[e+6]<128&&t[e+7]<128&&t[e+8]<128&&t[e+9]<128},a=function(t,e){return e+10<=t.length&&51===t[e]&&68===t[e+1]&&73===t[e+2]&&t[e+3]<255&&t[e+4]<255&&t[e+6]<128&&t[e+7]<128&&t[e+8]<128&&t[e+9]<128},s=function(t,e){for(var i=e,r=0;n(t,e);){r+=10,r+=o(t,e+6),a(t,e+10)&&(r+=10),e+=r}if(r>0)return t.subarray(i,i+r)},o=function(t,e){var i=0;return i=(127&t[e])<<21,i|=(127&t[e+1])<<14,i|=(127&t[e+2])<<7,i|=127&t[e+3]},l=function(t,e){return n(t,e)&&o(t,e+6)+10<=t.length-e},u=function(t){for(var e=c(t),i=0;i>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:u+=String.fromCharCode(a);break;case 12:case 13:s=t[h++],u+=String.fromCharCode((31&a)<<6|63&s);break;case 14:s=t[h++],o=t[h++],u+=String.fromCharCode((15&a)<<12|(63&s)<<6|(63&o)<<0)}}return u};function T(){return r||void 0===self.TextDecoder||(r=new self.TextDecoder("utf-8")),r}},function(t,e,i){"use strict";var r;i.d(e,"a",(function(){return r})),function(t){t.audioId3="org.id3",t.dateRange="com.apple.quicktime.HLS",t.emsg="https://aomedia.org/emsg/ID3"}(r||(r={}))},function(t,e,i){"use strict";function r(t,e,i){return Uint8Array.prototype.slice?t.slice(e,i):new Uint8Array(Array.prototype.slice.call(t,e,i))}i.d(e,"a",(function(){return r}))},function(t,e,i){"use strict";i.d(e,"c",(function(){return it})),i.d(e,"d",(function(){return nt})),i.d(e,"a",(function(){return at})),i.d(e,"b",(function(){return st}));var r=i(0),n=i(2),a=i(16),s=i(3),o=i(7),l=i(8);function u(t,e){return void 0===t&&(t=""),void 0===e&&(e=9e4),{type:t,id:-1,pid:-1,inputTimeScale:e,sequenceNumber:-1,samples:[],dropped:0}}var h=i(5),d=i(9),c=function(){function t(){this._audioTrack=void 0,this._id3Track=void 0,this.frameIndex=0,this.cachedData=null,this.basePTS=null,this.initPTS=null}var e=t.prototype;return e.resetInitSegment=function(t,e,i,r){this._id3Track={type:"id3",id:3,pid:-1,inputTimeScale:9e4,sequenceNumber:0,samples:[],dropped:0}},e.resetTimeStamp=function(t){this.initPTS=t,this.resetContiguity()},e.resetContiguity=function(){this.basePTS=null,this.frameIndex=0},e.canParse=function(t,e){return!1},e.appendFrame=function(t,e,i){},e.demux=function(t,e){this.cachedData&&(t=Object(h.b)(this.cachedData,t),this.cachedData=null);var i,r,n=o.b(t,0),a=n?n.length:0,c=this._audioTrack,g=this._id3Track,v=n?o.d(n):void 0,p=t.length;for((null===this.basePTS||0===this.frameIndex&&Object(s.a)(v))&&(this.basePTS=f(v,e,this.initPTS)),n&&n.length>0&&g.samples.push({pts:this.basePTS,dts:this.basePTS,data:n,type:l.a.audioId3}),r=this.basePTS;a>>5}function T(t,e){return e+1=t.length)return!1;var r=y(t,e);if(r<=i)return!1;var n=e+r;return n===t.length||T(t,n)}return!1}function E(t,e,i,a,s){if(!t.samplerate){var o=function(t,e,i,a){var s,o,l,u,h=navigator.userAgent.toLowerCase(),d=a,c=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350];s=1+((192&e[i+2])>>>6);var f=(60&e[i+2])>>>2;if(!(f>c.length-1))return l=(1&e[i+2])<<2,l|=(192&e[i+3])>>>6,v.b.log("manifest codec:"+a+", ADTS type:"+s+", samplingIndex:"+f),/firefox/i.test(h)?f>=6?(s=5,u=new Array(4),o=f-3):(s=2,u=new Array(2),o=f):-1!==h.indexOf("android")?(s=2,u=new Array(2),o=f):(s=5,u=new Array(4),a&&(-1!==a.indexOf("mp4a.40.29")||-1!==a.indexOf("mp4a.40.5"))||!a&&f>=6?o=f-3:((a&&-1!==a.indexOf("mp4a.40.2")&&(f>=6&&1===l||/vivaldi/i.test(h))||!a&&1===l)&&(s=2,u=new Array(2)),o=f)),u[0]=s<<3,u[0]|=(14&f)>>1,u[1]|=(1&f)<<7,u[1]|=l<<3,5===s&&(u[1]|=(14&o)>>1,u[2]=(1&o)<<7,u[2]|=8,u[3]=0),{config:u,samplerate:c[f],channelCount:l,codec:"mp4a.40."+s,manifestCodec:d};t.trigger(r.a.ERROR,{type:n.b.MEDIA_ERROR,details:n.a.FRAG_PARSING_ERROR,fatal:!0,reason:"invalid ADTS sampling index:"+f})}(e,i,a,s);if(!o)return;t.config=o.config,t.samplerate=o.samplerate,t.channelCount=o.channelCount,t.codec=o.codec,t.manifestCodec=o.manifestCodec,v.b.log("parsed codec:"+t.codec+", rate:"+o.samplerate+", channels:"+o.channelCount)}}function S(t){return 9216e4/t}function L(t,e,i,r,n){var a,s=r+n*S(t.samplerate),o=function(t,e){var i=m(t,e);if(e+i<=t.length){var r=y(t,e)-i;if(r>0)return{headerLength:i,frameLength:r}}}(e,i);if(o){var l=o.frameLength,u=o.headerLength,h=u+l,d=Math.max(0,i+h-e.length);d?(a=new Uint8Array(h-u)).set(e.subarray(i+u,e.length),0):a=e.subarray(i+u,i+h);var c={unit:a,pts:s};return d||t.samples.push(c),{sample:c,length:h,missing:d}}var f=e.length-i;return(a=new Uint8Array(f)).set(e.subarray(i,e.length),0),{sample:{unit:a,pts:s},length:f,missing:-1}}function A(t,e){return(A=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}var D=function(t){var e,i;function r(e,i){var r;return(r=t.call(this)||this).observer=void 0,r.config=void 0,r.observer=e,r.config=i,r}i=t,(e=r).prototype=Object.create(i.prototype),e.prototype.constructor=e,A(e,i);var n=r.prototype;return n.resetInitSegment=function(e,i,r,n){t.prototype.resetInitSegment.call(this,e,i,r,n),this._audioTrack={container:"audio/adts",type:"audio",id:2,pid:-1,sequenceNumber:0,segmentCodec:"aac",samples:[],manifestCodec:i,duration:n,inputTimeScale:9e4,dropped:0}},r.probe=function(t){if(!t)return!1;for(var e=(o.b(t,0)||[]).length,i=t.length;e16384?t.subarray(0,16384):t,Object(h.c)(t,["moof"]).length>0},e.demux=function(t,e){this.timeOffset=e;var i=t,r=this.videoTrack,n=this.txtTrack;if(this.config.progressive){this.remainderData&&(i=Object(h.b)(this.remainderData,t));var a=Object(h.l)(i);this.remainderData=a.remainder,r.samples=a.valid||new Uint8Array}else r.samples=i;var s=this.extractID3Track(r,e);return n.samples=Object(h.j)(e,r),{videoTrack:r,audioTrack:this.audioTrack,id3Track:s,textTrack:this.txtTrack}},e.flush=function(){var t=this.timeOffset,e=this.videoTrack,i=this.txtTrack;e.samples=this.remainderData||new Uint8Array,this.remainderData=null;var r=this.extractID3Track(e,this.timeOffset);return i.samples=Object(h.j)(t,e),{videoTrack:e,audioTrack:u(),id3Track:r,textTrack:u()}},e.extractID3Track=function(t,e){var i=this.id3Track;if(t.samples.length){var r=Object(h.c)(t.samples,["emsg"]);r&&r.forEach((function(t){var r=Object(h.g)(t);if(R.test(r.schemeIdUri)){var n=Object(s.a)(r.presentationTime)?r.presentationTime/r.timeScale:e+r.presentationTimeDelta/r.timeScale,a=r.payload;i.samples.push({data:a,len:a.byteLength,dts:n,pts:n,type:l.a.emsg})}}))}return i},e.demuxSampleAes=function(t,e,i){return Promise.reject(new Error("The MP4 demuxer does not support SAMPLE-AES decryption"))},e.destroy=function(){},t}(),_=null,I=[32,64,96,128,160,192,224,256,288,320,352,384,416,448,32,48,56,64,80,96,112,128,160,192,224,256,320,384,32,40,48,56,64,80,96,112,128,160,192,224,256,320,32,48,56,64,80,96,112,128,144,160,176,192,224,256,8,16,24,32,40,48,56,64,80,96,112,128,144,160],O=[44100,48e3,32e3,22050,24e3,16e3,11025,12e3,8e3],C=[[0,72,144,12],[0,0,0,0],[0,72,144,12],[0,144,144,12]],w=[0,1,1,4];function x(t,e,i,r,n){if(!(i+24>e.length)){var a=P(e,i);if(a&&i+a.frameLength<=e.length){var s=r+n*(9e4*a.samplesPerFrame/a.sampleRate),o={unit:e.subarray(i,i+a.frameLength),pts:s,dts:s};return t.config=[],t.channelCount=a.channelCount,t.samplerate=a.sampleRate,t.samples.push(o),{sample:o,length:a.frameLength,missing:0}}}}function P(t,e){var i=t[e+1]>>3&3,r=t[e+1]>>1&3,n=t[e+2]>>4&15,a=t[e+2]>>2&3;if(1!==i&&0!==n&&15!==n&&3!==a){var s=t[e+2]>>1&1,o=t[e+3]>>6,l=1e3*I[14*(3===i?3-r:3===r?3:4)+n-1],u=O[3*(3===i?0:2===i?1:2)+a],h=3===o?1:2,d=C[i][r],c=w[r],f=8*d*c,g=Math.floor(d*l/u+s)*c;if(null===_){var v=(navigator.userAgent||"").match(/Chrome\/(\d+)/i);_=v?parseInt(v[1]):0}return!!_&&_<=87&&2===r&&l>=224e3&&0===o&&(t[e+3]=128|t[e+3]),{sampleRate:u,channelCount:h,frameLength:g,samplesPerFrame:f}}}function F(t,e){return 255===t[e]&&224==(224&t[e+1])&&0!=(6&t[e+1])}function M(t,e){return e+1t?(this.word<<=t,this.bitsAvailable-=t):(t-=this.bitsAvailable,t-=(e=t>>3)>>3,this.bytesAvailable-=e,this.loadWord(),this.word<<=t,this.bitsAvailable-=t)},e.readBits=function(t){var e=Math.min(this.bitsAvailable,t),i=this.word>>>32-e;return t>32&&v.b.error("Cannot read more than 32 bits at a time"),this.bitsAvailable-=e,this.bitsAvailable>0?this.word<<=e:this.bytesAvailable>0&&this.loadWord(),(e=t-e)>0&&this.bitsAvailable?i<>>t))return this.word<<=t,this.bitsAvailable-=t,t;return this.loadWord(),t+this.skipLZ()},e.skipUEG=function(){this.skipBits(1+this.skipLZ())},e.skipEG=function(){this.skipBits(1+this.skipLZ())},e.readUEG=function(){var t=this.skipLZ();return this.readBits(t+1)-1},e.readEG=function(){var t=this.readUEG();return 1&t?1+t>>>1:-1*(t>>>1)},e.readBoolean=function(){return 1===this.readBits(1)},e.readUByte=function(){return this.readBits(8)},e.readUShort=function(){return this.readBits(16)},e.readUInt=function(){return this.readBits(32)},e.skipScalingList=function(t){for(var e=8,i=8,r=0;r=t.length)return void i();if(!(t[e].unit.length<32)){var r=this.decrypter.isSync();if(this.decryptAacSample(t,e,i,r),!r)return}}},e.getAvcEncryptedData=function(t){for(var e=16*Math.floor((t.length-48)/160)+16,i=new Int8Array(e),r=0,n=32;n=t.length)return void r();for(var n=t[e].units;!(i>=n.length);i++){var a=n[i];if(!(a.data.length<=48||1!==a.type&&5!==a.type)){var s=this.decrypter.isSync();if(this.decryptAvcSample(t,e,i,r,a,s),!s)return}}}},t}();function G(){return(G=Object.assign?Object.assign.bind():function(t){for(var e=1;e1;){var l=new Uint8Array(o[0].length+o[1].length);l.set(o[0]),l.set(o[1],o[0].length),o[0]=l,o.splice(1,1)}if(1===((e=o[0])[0]<<16)+(e[1]<<8)+e[2]){if((i=(e[4]<<8)+e[5])&&i>t.size-6)return null;var u=e[7];192&u&&(n=536870912*(14&e[9])+4194304*(255&e[10])+16384*(254&e[11])+128*(255&e[12])+(254&e[13])/2,64&u?n-(a=536870912*(14&e[14])+4194304*(255&e[15])+16384*(254&e[16])+128*(255&e[17])+(254&e[18])/2)>54e5&&(v.b.warn(Math.round((n-a)/9e4)+"s delta between PTS and DTS, align them"),n=a):a=n);var h=(r=e[8])+9;if(t.size<=h)return null;t.size-=h;for(var d=new Uint8Array(t.size),c=0,f=o.length;cg){h-=g;continue}e=e.subarray(h),g-=h,h=0}d.set(e,s),s+=g}return i&&(i-=r+3),{data:d,pts:n,dts:a,len:i}}return null}function W(t,e){if(t.units.length&&t.frame){if(void 0===t.pts){var i=e.samples,r=i.length;if(!r)return void e.dropped++;var n=i[r-1];t.pts=n.pts,t.dts=n.dts}e.samples.push(t)}t.debug.length&&v.b.log(t.pts+"/"+t.dts+":"+t.debug)}function Y(t){for(var e=t.byteLength,i=[],r=1;r>4>1){if((k=A+5+t[A+4])===A+188)continue}else k=A+4;switch(R){case c:D&&(f&&(s=V(f))&&this.parseAVCPES(o,d,s,!1),f={data:[],size:0}),f&&(f.data.push(t.subarray(k,A+188)),f.size+=A+188-k);break;case g:if(D){if(m&&(s=V(m)))switch(l.segmentCodec){case"aac":this.parseAACPES(l,s);break;case"mp3":this.parseMPEGPES(l,s)}m={data:[],size:0}}m&&(m.data.push(t.subarray(k,A+188)),m.size+=A+188-k);break;case p:D&&(y&&(s=V(y))&&this.parseID3PES(u,s),y={data:[],size:0}),y&&(y.data.push(t.subarray(k,A+188)),y.size+=A+188-k);break;case 0:D&&(k+=t[k]+1),E=this._pmtId=K(t,k);break;case E:D&&(k+=t[k]+1);var _=H(t,k,this.typeSupported,i);(c=_.avc)>0&&(o.pid=c),(g=_.audio)>0&&(l.pid=g,l.segmentCodec=_.segmentCodec),(p=_.id3)>0&&(u.pid=p),null===T||b||(v.b.log("unknown PID '"+T+"' in TS found"),T=null),b=this.pmtParsed=!0;break;case 17:case 8191:break;default:T=R}}else L++;L>0&&this.observer.emit(r.a.ERROR,r.a.ERROR,{type:n.b.MEDIA_ERROR,details:n.a.FRAG_PARSING_ERROR,fatal:!1,reason:"Found "+L+" TS packet/s that do not start with 0x47"}),o.pesData=f,l.pesData=m,u.pesData=y;var I={audioTrack:l,videoTrack:o,id3Track:u,textTrack:d};return a&&this.extractRemainingSamples(I),I},e.flush=function(){var t,e=this.remainderData;return this.remainderData=null,t=e?this.demux(e,-1,!1,!0):{videoTrack:this._avcTrack,audioTrack:this._audioTrack,id3Track:this._id3Track,textTrack:this._txtTrack},this.extractRemainingSamples(t),this.sampleAes?this.decrypt(t,this.sampleAes):t},e.extractRemainingSamples=function(t){var e,i=t.audioTrack,r=t.videoTrack,n=t.id3Track,a=t.textTrack,s=r.pesData,o=i.pesData,l=n.pesData;if(s&&(e=V(s))?(this.parseAVCPES(r,a,e,!0),r.pesData=null):r.pesData=s,o&&(e=V(o))){switch(i.segmentCodec){case"aac":this.parseAACPES(i,e);break;case"mp3":this.parseMPEGPES(i,e)}i.pesData=null}else null!=o&&o.size&&v.b.log("last AAC PES packet truncated,might overlap between fragments"),i.pesData=o;l&&(e=V(l))?(this.parseID3PES(n,e),n.pesData=null):n.pesData=l},e.demuxSampleAes=function(t,e,i){var r=this.demux(t,i,!0,!this.config.progressive),n=this.sampleAes=new B(this.observer,this.config,e);return this.decrypt(r,n)},e.decrypt=function(t,e){return new Promise((function(i){var r=t.audioTrack,n=t.videoTrack;r.samples&&"aac"===r.segmentCodec?e.decryptAacSamples(r.samples,0,(function(){n.samples?e.decryptAvcSamples(n.samples,0,0,(function(){i(t)})):i(t)})):n.samples&&e.decryptAvcSamples(n.samples,0,0,(function(){i(t)}))}))},e.destroy=function(){this._duration=0},e.parseAVCPES=function(t,e,i,r){var n,a=this,s=this.parseAVCNALu(t,i.data),o=this.avcSample,l=!1;i.data=null,o&&s.length&&!t.audFound&&(W(o,t),o=this.avcSample=j(!1,i.pts,i.dts,"")),s.forEach((function(r){switch(r.type){case 1:n=!0,o||(o=a.avcSample=j(!0,i.pts,i.dts,"")),o.frame=!0;var s=r.data;if(l&&s.length>4){var u=new U(s).readSliceType();2!==u&&4!==u&&7!==u&&9!==u||(o.key=!0)}break;case 5:n=!0,o||(o=a.avcSample=j(!0,i.pts,i.dts,"")),o.key=!0,o.frame=!0;break;case 6:n=!0,Object(h.i)(Y(r.data),i.pts,e.samples);break;case 7:if(n=!0,l=!0,!t.sps){var d=new U(r.data).readSPS();t.width=d.width,t.height=d.height,t.pixelRatio=d.pixelRatio,t.sps=[r.data],t.duration=a._duration;for(var c=r.data.subarray(1,4),f="avc1.",g=0;g<3;g++){var v=c[g].toString(16);v.length<2&&(v="0"+v),f+=v}t.codec=f}break;case 8:n=!0,t.pps||(t.pps=[r.data]);break;case 9:n=!1,t.audFound=!0,o&&W(o,t),o=a.avcSample=j(!1,i.pts,i.dts,"");break;case 12:n=!0;break;default:n=!1,o&&(o.debug+="unknown NAL "+r.type+" ")}o&&n&&o.units.push(r)})),r&&o&&(W(o,t),this.avcSample=null)},e.getLastNalUnit=function(t){var e,i,r=this.avcSample;if(r&&0!==r.units.length||(r=t[t.length-1]),null!==(e=r)&&void 0!==e&&e.units){var n=r.units;i=n[n.length-1]}return i},e.parseAVCNALu=function(t,e){var i,r,n=e.byteLength,a=t.naluState||0,s=a,o=[],l=0,u=-1,h=0;for(-1===a&&(u=0,h=31&e[0],a=0,l=1);l=0){var d={data:e.subarray(u,l-a-1),type:h};o.push(d)}else{var c=this.getLastNalUnit(t.samples);if(c&&(s&&l<=4-s&&c.state&&(c.data=c.data.subarray(0,c.data.byteLength-s)),(r=l-a-1)>0)){var f=new Uint8Array(c.data.byteLength+r);f.set(c.data,0),f.set(e.subarray(0,r),c.data.byteLength),c.data=f,c.state=0}}l=0&&a>=0){var g={data:e.subarray(u,n),type:h,state:a};o.push(g)}if(0===o.length){var v=this.getLastNalUnit(t.samples);if(v){var p=new Uint8Array(v.data.byteLength+e.byteLength);p.set(v.data,0),p.set(e,v.data.byteLength),v.data=p}}return t.naluState=a,o},e.parseAACPES=function(t,e){var i,a,s,o,l,u=0,h=this.aacOverFlow,d=e.data;if(h){this.aacOverFlow=null;var c=h.missing,f=h.sample.unit.byteLength;if(-1===c){var g=new Uint8Array(f+d.byteLength);g.set(h.sample.unit,0),g.set(d,f),d=g}else{var p=f-c;h.sample.unit.set(d.subarray(0,c),p),t.samples.push(h.sample),u=h.missing}}for(i=u,a=d.length;i4?i:"hvc1"===i||"hev1"===i?"hvc1.1.c.L120.90":"av01"===i?"av01.0.04M.08":"avc1"===i||e===$.a.VIDEO?"avc1.42e01e":"mp4a.40.5"}var Z,tt=function(){function t(){this.emitInitSegment=!1,this.audioCodec=void 0,this.videoCodec=void 0,this.initData=void 0,this.initPTS=void 0,this.initTracks=void 0,this.lastEndTime=null}var e=t.prototype;return e.destroy=function(){},e.resetTimeStamp=function(t){this.initPTS=t,this.lastEndTime=null},e.resetNextTimestamp=function(){this.lastEndTime=null},e.resetInitSegment=function(t,e,i){this.audioCodec=e,this.videoCodec=i,this.generateInitSegment(t),this.emitInitSegment=!0},e.generateInitSegment=function(t){var e=this.audioCodec,i=this.videoCodec;if(!t||!t.byteLength)return this.initTracks=void 0,void(this.initData=void 0);var r=this.initData=Object(h.h)(t);e||(e=J(r.audio,$.a.AUDIO)),i||(i=J(r.video,$.a.VIDEO));var n={};r.audio&&r.video?n.audiovideo={container:"video/mp4",codec:e+","+i,initSegment:t,id:"main"}:r.audio?n.audio={container:"audio/mp4",codec:e,initSegment:t,id:"audio"}:r.video?n.video={container:"video/mp4",codec:i,initSegment:t,id:"main"}:v.b.warn("[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes."),this.initTracks=n},e.remux=function(t,e,i,r,n){var a,o=this.initPTS,l=this.lastEndTime,u={audio:void 0,video:void 0,text:r,id3:i,initSegment:void 0};Object(s.a)(l)||(l=this.lastEndTime=n||0);var d=e.samples;if(!d||!d.length)return u;var c={initPTS:void 0,timescale:1},f=this.initData;if(f&&f.length||(this.generateInitSegment(d),f=this.initData),!f||!f.length)return v.b.warn("[passthrough-remuxer.ts]: Failed to generate initSegment."),u;this.emitInitSegment&&(c.tracks=this.initTracks,this.emitInitSegment=!1);var g=Object(h.e)(f,d);Object(s.a)(o)||(this.initPTS=c.initPTS=o=g-n);var p=Object(h.d)(d,f),m=t?g-o:l,y=m+p;Object(h.f)(f,d,o),p>0?this.lastEndTime=y:(v.b.warn("Duration parsed from mp4 should be greater than zero"),this.resetNextTimestamp());var T=!!f.audio,b=!!f.video,E="";T&&(E+="audio"),b&&(E+="video");var S={data1:d,startPTS:m,startDTS:m,endPTS:y,endDTS:y,type:E,hasAudio:T,hasVideo:b,nb:1,dropped:0};u.audio="audio"===S.type?S:void 0,u.video="audio"!==S.type?S:void 0,u.initSegment=c;var L=null!=(a=this.initPTS)?a:0;return u.id3=Object(Q.b)(i,n,L,L),r.samples.length&&(u.text=Object(Q.c)(r,n,L)),u},t}();try{Z=self.performance.now.bind(self.performance)}catch(t){v.b.debug("Unable to use Performance API on this environment"),Z=self.Date.now}var et=[{demux:q,remux:Q.a},{demux:k,remux:tt},{demux:D,remux:Q.a},{demux:X,remux:Q.a}],it=function(){function t(t,e,i,r,n){this.observer=void 0,this.typeSupported=void 0,this.config=void 0,this.vendor=void 0,this.id=void 0,this.demuxer=void 0,this.remuxer=void 0,this.decrypter=void 0,this.probe=void 0,this.decryptionPromise=null,this.transmuxConfig=void 0,this.currentTransmuxState=void 0,this.observer=t,this.typeSupported=e,this.config=i,this.vendor=r,this.id=n}var e=t.prototype;return e.configure=function(t){this.transmuxConfig=t,this.decrypter&&this.decrypter.reset()},e.push=function(t,e,i,r){var n=this,a=i.transmuxing;a.executeStart=Z();var s=new Uint8Array(t),o=this.config,l=this.currentTransmuxState,u=this.transmuxConfig;r&&(this.currentTransmuxState=r);var h=r||l,d=h.contiguous,c=h.discontinuity,f=h.trackSwitch,g=h.accurateTimeOffset,v=h.timeOffset,p=h.initSegmentChange,m=u.audioCodec,y=u.videoCodec,T=u.defaultInitPts,b=u.duration,E=u.initSegmentData;(c||f||p)&&this.resetInitSegment(E,m,y,b),(c||p)&&this.resetInitialTimestamp(T),d||this.resetContiguity();var S=function(t,e){var i=null;t.byteLength>0&&null!=e&&null!=e.key&&null!==e.iv&&null!=e.method&&(i=e);return i}(s,e);if(S&&"AES-128"===S.method){var L=this.getDecrypter();if(!o.enableSoftwareAES)return this.decryptionPromise=L.webCryptoDecrypt(s,S.key.buffer,S.iv.buffer).then((function(t){var e=n.push(t,null,i);return n.decryptionPromise=null,e})),this.decryptionPromise;var A=L.softwareDecrypt(s,S.key.buffer,S.iv.buffer);if(!A)return a.executeEnd=Z(),rt(i);s=new Uint8Array(A)}this.needsProbing(s,c,f)&&this.configureTransmuxer(s,u);var D=this.transmux(s,S,v,g,i),R=this.currentTransmuxState;return R.contiguous=!0,R.discontinuity=!1,R.trackSwitch=!1,a.executeEnd=Z(),D},e.flush=function(t){var e=this,i=t.transmuxing;i.executeStart=Z();var a=this.decrypter,s=this.currentTransmuxState,o=this.decryptionPromise;if(o)return o.then((function(){return e.flush(t)}));var l=[],u=s.timeOffset;if(a){var h=a.flush();h&&l.push(this.push(h,null,t))}var d=this.demuxer,c=this.remuxer;if(!d||!c)return this.observer.emit(r.a.ERROR,r.a.ERROR,{type:n.b.MEDIA_ERROR,details:n.a.FRAG_PARSING_ERROR,fatal:!0,reason:"no demux matching with content found"}),i.executeEnd=Z(),[rt(t)];var f=d.flush(u);return nt(f)?f.then((function(i){return e.flushRemux(l,i,t),l})):(this.flushRemux(l,f,t),l)},e.flushRemux=function(t,e,i){var r=e.audioTrack,n=e.videoTrack,a=e.id3Track,s=e.textTrack,o=this.currentTransmuxState,l=o.accurateTimeOffset,u=o.timeOffset;v.b.log("[transmuxer.ts]: Flushed fragment "+i.sn+(i.part>-1?" p: "+i.part:"")+" of level "+i.level);var h=this.remuxer.remux(r,n,a,s,u,l,!0,this.id);t.push({remuxResult:h,chunkMeta:i}),i.transmuxing.executeEnd=Z()},e.resetInitialTimestamp=function(t){var e=this.demuxer,i=this.remuxer;e&&i&&(e.resetTimeStamp(t),i.resetTimeStamp(t))},e.resetContiguity=function(){var t=this.demuxer,e=this.remuxer;t&&e&&(t.resetContiguity(),e.resetNextTimestamp())},e.resetInitSegment=function(t,e,i,r){var n=this.demuxer,a=this.remuxer;n&&a&&(n.resetInitSegment(t,e,i,r),a.resetInitSegment(t,e,i))},e.destroy=function(){this.demuxer&&(this.demuxer.destroy(),this.demuxer=void 0),this.remuxer&&(this.remuxer.destroy(),this.remuxer=void 0)},e.transmux=function(t,e,i,r,n){return e&&"SAMPLE-AES"===e.method?this.transmuxSampleAes(t,e,i,r,n):this.transmuxUnencrypted(t,i,r,n)},e.transmuxUnencrypted=function(t,e,i,r){var n=this.demuxer.demux(t,e,!1,!this.config.progressive),a=n.audioTrack,s=n.videoTrack,o=n.id3Track,l=n.textTrack;return{remuxResult:this.remuxer.remux(a,s,o,l,e,i,!1,this.id),chunkMeta:r}},e.transmuxSampleAes=function(t,e,i,r,n){var a=this;return this.demuxer.demuxSampleAes(t,e,i).then((function(t){return{remuxResult:a.remuxer.remux(t.audioTrack,t.videoTrack,t.id3Track,t.textTrack,i,r,!1,a.id),chunkMeta:n}}))},e.configureTransmuxer=function(t,e){for(var i,r=this.config,n=this.observer,a=this.typeSupported,s=this.vendor,o=e.audioCodec,l=e.defaultInitPts,u=e.duration,h=e.initSegmentData,d=e.videoCodec,c=0,f=et.length;c1?i-1:0),n=1;n>24&255,o[1]=e>>16&255,o[2]=e>>8&255,o[3]=255&e,o.set(t,4),a=0,e=8;a>24&255,e>>16&255,e>>8&255,255&e,r>>24,r>>16&255,r>>8&255,255&r,n>>24,n>>16&255,n>>8&255,255&n,85,196,0,0]))},t.mdia=function(e){return t.box(t.types.mdia,t.mdhd(e.timescale,e.duration),t.hdlr(e.type),t.minf(e))},t.mfhd=function(e){return t.box(t.types.mfhd,new Uint8Array([0,0,0,0,e>>24,e>>16&255,e>>8&255,255&e]))},t.minf=function(e){return"audio"===e.type?t.box(t.types.minf,t.box(t.types.smhd,t.SMHD),t.DINF,t.stbl(e)):t.box(t.types.minf,t.box(t.types.vmhd,t.VMHD),t.DINF,t.stbl(e))},t.moof=function(e,i,r){return t.box(t.types.moof,t.mfhd(e),t.traf(r,i))},t.moov=function(e){for(var i=e.length,r=[];i--;)r[i]=t.trak(e[i]);return t.box.apply(null,[t.types.moov,t.mvhd(e[0].timescale,e[0].duration)].concat(r).concat(t.mvex(e)))},t.mvex=function(e){for(var i=e.length,r=[];i--;)r[i]=t.trex(e[i]);return t.box.apply(null,[t.types.mvex].concat(r))},t.mvhd=function(e,i){i*=e;var r=Math.floor(i/(a+1)),n=Math.floor(i%(a+1)),s=new Uint8Array([1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,e>>24&255,e>>16&255,e>>8&255,255&e,r>>24,r>>16&255,r>>8&255,255&r,n>>24,n>>16&255,n>>8&255,255&n,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return t.box(t.types.mvhd,s)},t.sdtp=function(e){var i,r,n=e.samples||[],a=new Uint8Array(4+n.length);for(i=0;i>>8&255),a.push(255&n),a=a.concat(Array.prototype.slice.call(r));for(i=0;i>>8&255),s.push(255&n),s=s.concat(Array.prototype.slice.call(r));var o=t.box(t.types.avcC,new Uint8Array([1,a[3],a[4],a[5],255,224|e.sps.length].concat(a).concat([e.pps.length]).concat(s))),l=e.width,u=e.height,h=e.pixelRatio[0],d=e.pixelRatio[1];return t.box(t.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,l>>8&255,255&l,u>>8&255,255&u,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,100,97,105,108,121,109,111,116,105,111,110,47,104,108,115,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,t.box(t.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])),t.box(t.types.pasp,new Uint8Array([h>>24,h>>16&255,h>>8&255,255&h,d>>24,d>>16&255,d>>8&255,255&d])))},t.esds=function(t){var e=t.config.length;return new Uint8Array([0,0,0,0,3,23+e,0,1,0,4,15+e,64,21,0,0,0,0,0,0,0,0,0,0,0,5].concat([e]).concat(t.config).concat([6,1,2]))},t.mp4a=function(e){var i=e.samplerate;return t.box(t.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount,0,16,0,0,0,0,i>>8&255,255&i,0,0]),t.box(t.types.esds,t.esds(e)))},t.mp3=function(e){var i=e.samplerate;return t.box(t.types[".mp3"],new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount,0,16,0,0,0,0,i>>8&255,255&i,0,0]))},t.stsd=function(e){return"audio"===e.type?"mp3"===e.segmentCodec&&"mp3"===e.codec?t.box(t.types.stsd,t.STSD,t.mp3(e)):t.box(t.types.stsd,t.STSD,t.mp4a(e)):t.box(t.types.stsd,t.STSD,t.avc1(e))},t.tkhd=function(e){var i=e.id,r=e.duration*e.timescale,n=e.width,s=e.height,o=Math.floor(r/(a+1)),l=Math.floor(r%(a+1));return t.box(t.types.tkhd,new Uint8Array([1,0,0,7,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,i>>24&255,i>>16&255,i>>8&255,255&i,0,0,0,0,o>>24,o>>16&255,o>>8&255,255&o,l>>24,l>>16&255,l>>8&255,255&l,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,n>>8&255,255&n,0,0,s>>8&255,255&s,0,0]))},t.traf=function(e,i){var r=t.sdtp(e),n=e.id,s=Math.floor(i/(a+1)),o=Math.floor(i%(a+1));return t.box(t.types.traf,t.box(t.types.tfhd,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n])),t.box(t.types.tfdt,new Uint8Array([1,0,0,0,s>>24,s>>16&255,s>>8&255,255&s,o>>24,o>>16&255,o>>8&255,255&o])),t.trun(e,r.length+16+20+8+16+8+8),r)},t.trak=function(e){return e.duration=e.duration||4294967295,t.box(t.types.trak,t.tkhd(e),t.mdia(e))},t.trex=function(e){var i=e.id;return t.box(t.types.trex,new Uint8Array([0,0,0,0,i>>24,i>>16&255,i>>8&255,255&i,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))},t.trun=function(e,i){var r,n,a,s,o,l,u=e.samples||[],h=u.length,d=12+16*h,c=new Uint8Array(d);for(i+=8+d,c.set(["video"===e.type?1:0,0,15,1,h>>>24&255,h>>>16&255,h>>>8&255,255&h,i>>>24&255,i>>>16&255,i>>>8&255,255&i],0),r=0;r>>24&255,a>>>16&255,a>>>8&255,255&a,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,l>>>24&255,l>>>16&255,l>>>8&255,255&l],12+16*r);return t.box(t.types.trun,c)},t.initSegment=function(e){t.types||t.init();var i=t.moov(e),r=new Uint8Array(t.FTYP.byteLength+i.byteLength);return r.set(t.FTYP),r.set(i,t.FTYP.byteLength),r},t}();s.types=void 0,s.HDLR_TYPES=void 0,s.STTS=void 0,s.STSC=void 0,s.STCO=void 0,s.STSZ=void 0,s.VMHD=void 0,s.SMHD=void 0,s.STSD=void 0,s.FTYP=void 0,s.DINF=void 0;var o=s,l=i(0),u=i(2),h=i(1),d=i(4),c=i(11);function f(){return(f=Object.assign?Object.assign.bind():function(t){for(var e=1;e0?t:i.pts}),t[0].pts);return e&&h.b.debug("PTS rollover detected"),i},e.remux=function(t,e,i,r,n,a,s,o){var l,u,c,f,g,v,p=n,b=n,E=t.pid>-1,S=e.pid>-1,L=e.samples.length,A=t.samples.length>0,D=s&&L>0||L>1;if((!E||A)&&(!S||D)||this.ISGenerated||s){this.ISGenerated||(c=this.generateIS(t,e,n));var R,k=this.isVideoContiguous,_=-1;if(D&&(_=function(t){for(var e=0;e0){h.b.warn("[mp4-remuxer]: Dropped "+_+" out of "+L+" video samples due to a missing keyframe");var I=this.getVideoStartPts(e.samples);e.samples=e.samples.slice(_),e.dropped+=_,R=b+=(e.samples[0].pts-I)/e.inputTimeScale}else-1===_&&(h.b.warn("[mp4-remuxer]: No keyframe found out of "+L+" video samples"),v=!1);if(this.ISGenerated){if(A&&D){var O=this.getVideoStartPts(e.samples),C=(m(t.samples[0].pts,O)-O)/e.inputTimeScale;p+=Math.max(0,C),b+=Math.max(0,-C)}if(A){if(t.samplerate||(h.b.warn("[mp4-remuxer]: regenerate InitSegment as audio detected"),c=this.generateIS(t,e,n)),u=this.remuxAudio(t,p,this.isAudioContiguous,a,S||D||o===d.b.AUDIO?b:void 0),D){var w=u?u.endPTS-u.startPTS:0;e.inputTimeScale||(h.b.warn("[mp4-remuxer]: regenerate InitSegment as video detected"),c=this.generateIS(t,e,n)),l=this.remuxVideo(e,b,k,w)}}else D&&(l=this.remuxVideo(e,b,k,0));l&&(l.firstKeyFrame=_,l.independent=-1!==_,l.firstKeyFramePTS=R)}}return this.ISGenerated&&(i.samples.length&&(g=y(i,n,this._initPTS,this._initDTS)),r.samples.length&&(f=T(r,n,this._initPTS))),{audio:u,video:l,initSegment:c,independent:v,text:f,id3:g}},e.generateIS=function(t,e,i){var n,a,s,l=t.samples,u=e.samples,h=this.typeSupported,d={},c=!Object(r.a)(this._initPTS),f="audio/mp4";if(c&&(n=a=1/0),t.config&&l.length){switch(t.timescale=t.samplerate,t.segmentCodec){case"mp3":h.mpeg?(f="audio/mpeg",t.codec=""):h.mp3&&(t.codec="mp3")}d.audio={id:"audio",container:f,codec:t.codec,initSegment:"mp3"===t.segmentCodec&&h.mpeg?new Uint8Array(0):o.initSegment([t]),metadata:{channelCount:t.channelCount}},c&&(s=t.inputTimeScale,n=a=l[0].pts-Math.round(s*i))}if(e.sps&&e.pps&&u.length&&(e.timescale=e.inputTimeScale,d.video={id:"main",container:"video/mp4",codec:e.codec,initSegment:o.initSegment([e]),metadata:{width:e.width,height:e.height}},c)){s=e.inputTimeScale;var g=this.getVideoStartPts(u),v=Math.round(s*i);a=Math.min(a,m(u[0].dts,g)-v),n=Math.min(n,g-v)}if(Object.keys(d).length)return this.ISGenerated=!0,c&&(this._initPTS=n,this._initDTS=a),{tracks:d,initPTS:n,timescale:s}},e.remuxVideo=function(t,e,i,r){var n,a,s=t.inputTimeScale,d=t.samples,p=[],y=d.length,T=this._initPTS,E=this.nextAvcDts,S=8,L=this.videoSampleDuration,A=Number.POSITIVE_INFINITY,D=Number.NEGATIVE_INFINITY,R=!1;i&&null!==E||(E=e*s-(d[0].pts-m(d[0].dts,d[0].pts)));for(var k=0;k0?k-1:k].dts&&(R=!0)}R&&d.sort((function(t,e){var i=t.dts-e.dts,r=t.pts-e.pts;return i||r})),n=d[0].dts;var I=(a=d[d.length-1].dts)-n,O=I?Math.round(I/(y-1)):L||t.inputTimeScale/30;if(i){var C=n-E,w=C>O;if(w||C<-1){w?h.b.warn("AVC: "+Object(c.b)(C,!0)+" ms ("+C+"dts) hole between fragments detected, filling it"):h.b.warn("AVC: "+Object(c.b)(-C,!0)+" ms ("+C+"dts) overlapping between fragments detected"),n=E;var x=d[0].pts-C;d[0].dts=n,d[0].pts=x,h.b.log("Video: First PTS/DTS adjusted: "+Object(c.b)(x,!0)+"/"+Object(c.b)(n,!0)+", delta: "+Object(c.b)(C,!0)+" ms")}}n=Math.max(0,n);for(var P=0,F=0,M=0;M0?$.dts-d[Q-1].dts:O;if(at=Q>0?$.pts-d[Q-1].pts:O,st.stretchShortVideoTrack&&null!==this.nextAudioPts){var lt=Math.floor(st.maxBufferHole*s),ut=(r?A+r*s:this.nextAudioPts)-$.pts;ut>lt?((L=ut-ot)<0?L=ot:W=!0,h.b.log("[mp4-remuxer]: It is approximately "+ut/90+" ms to the next segment; using duration "+L/90+" ms for the last video frame.")):L=ot}else L=ot}var ht=Math.round($.pts-$.dts);Y=Math.min(Y,L),z=Math.max(z,L),q=Math.min(q,at),X=Math.max(X,at),p.push(new b($.key,L,Z,ht))}if(p.length)if(g){if(g<70){var dt=p[0].flags;dt.dependsOn=2,dt.isNonSync=0}}else if(v&&X-q0&&(r&&Math.abs(A-L)<9e3||Math.abs(m(E[0].pts-v,A)-L)<20*g),E.forEach((function(t){t.pts=m(t.pts-v,A)})),!i||L<0){if(!(E=E.filter((function(t){return t.pts>=0}))).length)return;L=0===a?0:r&&!T?Math.max(0,A):E[0].pts}if("aac"===t.segmentCodec)for(var D=this.config.maxAudioFramesDrift,R=0,k=L;R=D*g&&C<1e4&&T){var w=Math.round(O/g);(k=I-w*g)<0&&(w--,k+=g),0===R&&(this.nextAudioPts=L=k),h.b.warn("[mp4-remuxer]: Injecting "+w+" audio frame @ "+(k/s).toFixed(3)+"s due to "+Math.round(1e3*O/s)+" ms gap.");for(var x=0;x0))return;B+=S;try{M=new Uint8Array(B)}catch(t){return void this.observer.emit(l.a.ERROR,l.a.ERROR,{type:u.b.MUX_ERROR,details:u.a.REMUX_ALLOC_ERROR,fatal:!1,bytes:B,reason:"fail allocating audio mdat "+B})}p||(new DataView(M.buffer).setUint32(0,B),M.set(o.types.mdat,4))}M.set(V,S);var Y=V.byteLength;S+=Y,y.push(new b(!0,c,Y,0)),U=W}var q=y.length;if(q){var z=y[y.length-1];this.nextAudioPts=L=U+d*z.duration;var X=p?new Uint8Array(0):o.moof(t.sequenceNumber++,N/d,f({},t,{samples:y}));t.samples=[];var Q=N/s,$=L/s,J={data1:X,data2:M,startPTS:Q,endPTS:$,startDTS:Q,endDTS:$,type:"audio",hasAudio:!0,hasVideo:!1,nb:q};return this.isAudioContiguous=!0,J}},e.remuxEmptyAudio=function(t,e,i,r){var a=t.inputTimeScale,s=a/(t.samplerate?t.samplerate:a),o=this.nextAudioPts,l=(null!==o?o:r.startDTS*a)+this._initDTS,u=r.endDTS*a+this._initDTS,d=1024*s,c=Math.ceil((u-l)/d),f=n.getSilentFrame(t.manifestCodec||t.codec,t.channelCount);if(h.b.warn("[mp4-remuxer]: remux empty Audio"),f){for(var g=[],v=0;v4294967296;)t+=i;return t}function y(t,e,i,r){var n=t.samples.length;if(n){for(var a=t.inputTimeScale,s=0;s>>8^255&p^99,t[f]=p,e[p]=f;var m=c[f],y=c[m],T=c[y],b=257*c[p]^16843008*p;r[f]=b<<24|b>>>8,n[f]=b<<16|b>>>16,a[f]=b<<8|b>>>24,s[f]=b,b=16843009*T^65537*y^257*m^16843008*f,l[p]=b<<24|b>>>8,u[p]=b<<16|b>>>16,h[p]=b<<8|b>>>24,d[p]=b,f?(f=m^c[c[c[T^m]]],g^=c[c[g]]):f=g=1}},e.expandKey=function(t){for(var e=this.uint8ArrayToUint32Array_(t),i=!0,r=0;r0}),!1)}t.exports=function(t,e){e=e||{};var n={main:i.m},o=e.all?{main:Object.keys(n.main)}:function(t,e){for(var i={main:[e]},r={main:[]},n={main:{}};s(i);)for(var o=Object.keys(i),l=0;lNumber.MAX_SAFE_INTEGER?1/0:e},e.hexadecimalInteger=function(t){if(this[t]){var e=(this[t]||"0x").slice(2);e=(1&e.length?"0":"")+e;for(var i=new Uint8Array(e.length/2),r=0;rNumber.MAX_SAFE_INTEGER?1/0:e},e.decimalFloatingPoint=function(t){return parseFloat(this[t])},e.optionalFloat=function(t,e){var i=this[t];return i?parseFloat(i):e},e.enumeratedString=function(t){return this[t]},e.bool=function(t){return"YES"===this[t]},e.decimalResolution=function(t){var e=h.exec(this[t]);if(null!==e)return{width:parseInt(e[1],10),height:parseInt(e[2],10)}},t.parseAttrList=function(t){var e,i={};for(d.lastIndex=0;null!==(e=d.exec(t));){var r=e[2];0===r.indexOf('"')&&r.lastIndexOf('"')===r.length-1&&(r=r.slice(1,-1)),i[e[1]]=r}return i},t}();function f(){return(f=Object.assign?Object.assign.bind():function(t){for(var e=1;e=0)&&(!this.endOnNext||!!this.class)}}])&&g(e.prototype,i),n&&g(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}(),p=i(6);function m(t,e){for(var i=0;it.endSN||e>0||0===e&&i>0,this.updated||this.advanced?this.misses=Math.floor(.6*t.misses):this.misses=t.misses+1,this.availabilityDelay=t.availabilityDelay},e=t,(i=[{key:"hasProgramDateTime",get:function(){return!!this.fragments.length&&Object(a.a)(this.fragments[this.fragments.length-1].programDateTime)}},{key:"levelTargetDuration",get:function(){return this.averagetargetduration||this.targetduration||10}},{key:"drift",get:function(){var t=this.driftEndTime-this.driftStartTime;return t>0?1e3*(this.driftEnd-this.driftStart)/t:1}},{key:"edge",get:function(){return this.partEnd||this.fragmentEnd}},{key:"partEnd",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].end:this.fragmentEnd}},{key:"fragmentEnd",get:function(){var t;return null!==(t=this.fragments)&&void 0!==t&&t.length?this.fragments[this.fragments.length-1].end:0}},{key:"age",get:function(){return this.advancedDateTime?Math.max(Date.now()-this.advancedDateTime,0)/1e3:0}},{key:"lastPartIndex",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].index:-1}},{key:"lastPartSn",get:function(){var t;return null!==(t=this.partList)&&void 0!==t&&t.length?this.partList[this.partList.length-1].fragment.sn:this.endSN}}])&&m(e.prototype,i),r&&m(e,r),Object.defineProperty(e,"prototype",{writable:!1}),t}(),T=i(17),b={audio:{a3ds:!0,"ac-3":!0,"ac-4":!0,alac:!0,alaw:!0,dra1:!0,"dts+":!0,"dts-":!0,dtsc:!0,dtse:!0,dtsh:!0,"ec-3":!0,enca:!0,g719:!0,g726:!0,m4ae:!0,mha1:!0,mha2:!0,mhm1:!0,mhm2:!0,mlpa:!0,mp4a:!0,"raw ":!0,Opus:!0,samr:!0,sawb:!0,sawp:!0,sevc:!0,sqcp:!0,ssmv:!0,twos:!0,ulaw:!0},video:{avc1:!0,avc2:!0,avc3:!0,avc4:!0,avcp:!0,av01:!0,drac:!0,dva1:!0,dvav:!0,dvh1:!0,dvhe:!0,encv:!0,hev1:!0,hvc1:!0,mjp2:!0,mp4v:!0,mvc1:!0,mvc2:!0,mvc3:!0,mvc4:!0,resv:!0,rv60:!0,s263:!0,svc1:!0,svc2:!0,"vc-1":!0,vp08:!0,vp09:!0},text:{stpp:!0,wvtt:!0}};function E(t,e){return MediaSource.isTypeSupported((e||"video")+'/mp4;codecs="'+t+'"')}var S=/#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-SESSION-DATA:([^\r\n]*)[\r\n]+/g,L=/#EXT-X-MEDIA:(.*)/g,A=new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source,/(?!#) *(\S[\S ]*)/.source,/#EXT-X-BYTERANGE:*(.+)/.source,/#EXT-X-PROGRAM-DATE-TIME:(.+)/.source,/#.*/.source].join("|"),"g"),D=new RegExp([/#(EXTM3U)/.source,/#EXT-X-(DATERANGE|KEY|MAP|PART|PART-INF|PLAYLIST-TYPE|PRELOAD-HINT|RENDITION-REPORT|SERVER-CONTROL|SKIP|START):(.+)/.source,/#EXT-X-(BITRATE|DISCONTINUITY-SEQUENCE|MEDIA-SEQUENCE|TARGETDURATION|VERSION): *(\d+)/.source,/#EXT-X-(DISCONTINUITY|ENDLIST|GAP)/.source,/(#)([^:]*):(.*)/.source,/(#)(.*)(?:.*)\r?\n?/.source].join("|")),R=/\.(mp4|m4s|m4v|m4a)$/i;var k=function(){function t(){}return t.findGroup=function(t,e){for(var i=0;i2){var i=e.shift()+".";return i+=parseInt(e.shift()).toString(16),i+=("000"+parseInt(e.shift()).toString(16)).slice(-4)}return t},t.resolve=function(t,e){return n.buildAbsoluteURL(e,t,{alwaysNormalize:!0})},t.parseMasterPlaylist=function(e,i){var r,n=[],a=[],s={},o=!1;for(S.lastIndex=0;null!=(r=S.exec(e));)if(r[1]){var l,u=new c(r[1]),h={attrs:u,bitrate:u.decimalInteger("AVERAGE-BANDWIDTH")||u.decimalInteger("BANDWIDTH"),name:u.NAME,url:t.resolve(r[2],i)},d=u.decimalResolution("RESOLUTION");d&&(h.width=d.width,h.height=d.height),_((u.CODECS||"").split(/[ ,]+/).filter((function(t){return t})),h),h.videoCodec&&-1!==h.videoCodec.indexOf("avc1")&&(h.videoCodec=t.convertAVC1ToAVCOTI(h.videoCodec)),null!==(l=h.unknownCodecs)&&void 0!==l&&l.length||a.push(h),n.push(h)}else if(r[3]){var f=new c(r[3]);f["DATA-ID"]&&(o=!0,s[f["DATA-ID"]]=f)}return{levels:a.length>0&&a.length-1){l.b.warn("Keyformat "+$+" is not supported from the manifest");continue}if("identity"!==$)continue;Y&&(h=T.a.fromURL(e,q),q&&["AES-128","SAMPLE-AES","SAMPLE-AES-CENC"].indexOf(Y)>=0&&(h.method=Y,h.keyFormat=$,Q&&(h.keyID=Q),X&&(h.keyFormatVersions=X),h.iv=z));break;case"START":var J=new c(M).decimalFloatingPoint("TIME-OFFSET");Object(a.a)(J)&&(d.startTimeOffset=J);break;case"MAP":var Z=new c(M);if(k.duration){var tt=new p.b(r,e);C(tt,Z,i,h),g=tt,k.initSegment=g,g.rawProgramDateTime&&!k.rawProgramDateTime&&(k.rawProgramDateTime=g.rawProgramDateTime)}else C(k,Z,i,h),g=k,I=!0;break;case"SERVER-CONTROL":var et=new c(M);d.canBlockReload=et.bool("CAN-BLOCK-RELOAD"),d.canSkipUntil=et.optionalFloat("CAN-SKIP-UNTIL",0),d.canSkipDateRanges=d.canSkipUntil>0&&et.bool("CAN-SKIP-DATERANGES"),d.partHoldBack=et.optionalFloat("PART-HOLD-BACK",0),d.holdBack=et.optionalFloat("HOLD-BACK",0);break;case"PART-INF":var it=new c(M);d.partTarget=it.decimalFloatingPoint("PART-TARGET");break;case"PART":var rt=d.partList;rt||(rt=d.partList=[]);var nt=b>0?rt[rt.length-1]:void 0,at=b++,st=new p.c(new c(M),k,e,at,nt);rt.push(st),k.duration+=st.duration;break;case"PRELOAD-HINT":var ot=new c(M);d.preloadHint=ot;break;case"RENDITION-REPORT":var lt=new c(M);d.renditionReports=d.renditionReports||[],d.renditionReports.push(lt);break;default:l.b.warn("line parsed but not handled: "+o)}}}L&&!L.relurl?(f.pop(),E-=L.duration,d.partList&&(d.fragmentHint=L)):d.partList&&(O(k,L),k.cc=S,d.fragmentHint=k);var ut=f.length,ht=f[0],dt=f[ut-1];if((E+=d.skippedSegments*d.targetduration)>0&&ut&&dt){d.averagetargetduration=E/ut;var ct=dt.sn;d.endSN="initSegment"!==ct?ct:0,ht&&(d.startCC=ht.cc,ht.initSegment||d.fragments.every((function(t){return t.relurl&&(e=t.relurl,R.test(null!=(i=null===(r=n.parseURL(e))||void 0===r?void 0:r.path)?i:""));var e,i,r}))&&(l.b.warn("MP4 fragments found but no init segment (probably no MAP, incomplete M3U8), trying to fetch SIDX"),(k=new p.b(r,e)).relurl=dt.relurl,k.level=i,k.sn="initSegment",ht.initSegment=k,d.needSidxRanges=!0))}else d.endSN=0,d.startCC=0;return d.fragmentHint&&(E+=d.fragmentHint.duration),d.totalduration=E,d.endCC=S,_>0&&function(t,e){for(var i=t[e],r=e;r--;){var n=t[r];if(!n)return;n.programDateTime=i.programDateTime-1e3*n.duration,i=n}}(f,_),d},t}();function _(t,e){["video","audio","text"].forEach((function(i){var r=t.filter((function(t){return function(t,e){var i=b[e];return!!i&&!0===i[t.slice(0,4)]}(t,i)}));if(r.length){var n=r.filter((function(t){return 0===t.lastIndexOf("avc1",0)||0===t.lastIndexOf("mp4a",0)}));e[i+"Codec"]=n.length>0?n[0]:r[0],t=t.filter((function(t){return-1===r.indexOf(t)}))}})),e.unknownCodecs=t}function I(t,e,i){var r=e[i];r&&(t[i]=r)}function O(t,e){t.rawProgramDateTime?t.programDateTime=Date.parse(t.rawProgramDateTime):null!=e&&e.programDateTime&&(t.programDateTime=e.endProgramDateTime),Object(a.a)(t.programDateTime)||(t.programDateTime=null,t.rawProgramDateTime=null)}function C(t,e,i,r){t.relurl=e.URI,e.BYTERANGE&&t.setByteRange(e.BYTERANGE),t.level=i,t.sn="initSegment",r&&(t.levelkey=r),t.initSegment=null}var w=i(4);function x(t,e){var i=t.url;return void 0!==i&&0!==i.indexOf("data:")||(i=e.url),i}var P=function(){function t(t){this.hls=void 0,this.loaders=Object.create(null),this.hls=t,this.registerListeners()}var e=t.prototype;return e.startLoad=function(t){},e.stopLoad=function(){this.destroyInternalLoaders()},e.registerListeners=function(){var t=this.hls;t.on(s.a.MANIFEST_LOADING,this.onManifestLoading,this),t.on(s.a.LEVEL_LOADING,this.onLevelLoading,this),t.on(s.a.AUDIO_TRACK_LOADING,this.onAudioTrackLoading,this),t.on(s.a.SUBTITLE_TRACK_LOADING,this.onSubtitleTrackLoading,this)},e.unregisterListeners=function(){var t=this.hls;t.off(s.a.MANIFEST_LOADING,this.onManifestLoading,this),t.off(s.a.LEVEL_LOADING,this.onLevelLoading,this),t.off(s.a.AUDIO_TRACK_LOADING,this.onAudioTrackLoading,this),t.off(s.a.SUBTITLE_TRACK_LOADING,this.onSubtitleTrackLoading,this)},e.createInternalLoader=function(t){var e=this.hls.config,i=e.pLoader,r=e.loader,n=new(i||r)(e);return t.loader=n,this.loaders[t.type]=n,n},e.getInternalLoader=function(t){return this.loaders[t.type]},e.resetInternalLoader=function(t){this.loaders[t]&&delete this.loaders[t]},e.destroyInternalLoaders=function(){for(var t in this.loaders){var e=this.loaders[t];e&&e.destroy(),this.resetInternalLoader(t)}},e.destroy=function(){this.unregisterListeners(),this.destroyInternalLoaders()},e.onManifestLoading=function(t,e){var i=e.url;this.load({id:null,groupId:null,level:0,responseType:"text",type:w.a.MANIFEST,url:i,deliveryDirectives:null})},e.onLevelLoading=function(t,e){var i=e.id,r=e.level,n=e.url,a=e.deliveryDirectives;this.load({id:i,groupId:null,level:r,responseType:"text",type:w.a.LEVEL,url:n,deliveryDirectives:a})},e.onAudioTrackLoading=function(t,e){var i=e.id,r=e.groupId,n=e.url,a=e.deliveryDirectives;this.load({id:i,groupId:r,level:null,responseType:"text",type:w.a.AUDIO_TRACK,url:n,deliveryDirectives:a})},e.onSubtitleTrackLoading=function(t,e){var i=e.id,r=e.groupId,n=e.url,a=e.deliveryDirectives;this.load({id:i,groupId:r,level:null,responseType:"text",type:w.a.SUBTITLE_TRACK,url:n,deliveryDirectives:a})},e.load=function(t){var e,i,r,n,a,s,o=this.hls.config,u=this.getInternalLoader(t);if(u){var h=u.context;if(h&&h.url===t.url)return void l.b.trace("[playlist-loader]: playlist request ongoing");l.b.log("[playlist-loader]: aborting previous loader for type: "+t.type),u.abort()}switch(t.type){case w.a.MANIFEST:i=o.manifestLoadingMaxRetry,r=o.manifestLoadingTimeOut,n=o.manifestLoadingRetryDelay,a=o.manifestLoadingMaxRetryTimeout;break;case w.a.LEVEL:case w.a.AUDIO_TRACK:case w.a.SUBTITLE_TRACK:i=0,r=o.levelLoadingTimeOut;break;default:i=o.levelLoadingMaxRetry,r=o.levelLoadingTimeOut,n=o.levelLoadingRetryDelay,a=o.levelLoadingMaxRetryTimeout}if((u=this.createInternalLoader(t),null!==(e=t.deliveryDirectives)&&void 0!==e&&e.part)&&(t.type===w.a.LEVEL&&null!==t.level?s=this.hls.levels[t.level].details:t.type===w.a.AUDIO_TRACK&&null!==t.id?s=this.hls.audioTracks[t.id].details:t.type===w.a.SUBTITLE_TRACK&&null!==t.id&&(s=this.hls.subtitleTracks[t.id].details),s)){var d=s.partTarget,c=s.targetduration;d&&c&&(r=Math.min(1e3*Math.max(3*d,.8*c),r))}var f={timeout:r,maxRetry:i,retryDelay:n,maxRetryDelay:a,highWaterMark:0},g={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};u.load(t,f,g)},e.loadsuccess=function(t,e,i,r){if(void 0===r&&(r=null),i.isSidxRequest)return this.handleSidxRequest(t,i),void this.handlePlaylistLoaded(t,e,i,r);this.resetInternalLoader(i.type);var n=t.data;0===n.indexOf("#EXTM3U")?(e.parsing.start=performance.now(),n.indexOf("#EXTINF:")>0||n.indexOf("#EXT-X-TARGETDURATION:")>0?this.handleTrackOrLevelPlaylist(t,e,i,r):this.handleMasterPlaylist(t,e,i,r)):this.handleManifestParsingError(t,i,"no EXTM3U delimiter",r)},e.loaderror=function(t,e,i){void 0===i&&(i=null),this.handleNetworkError(e,i,!1,t)},e.loadtimeout=function(t,e,i){void 0===i&&(i=null),this.handleNetworkError(e,i,!0)},e.handleMasterPlaylist=function(t,e,i,r){var n=this.hls,a=t.data,o=x(t,i),u=k.parseMasterPlaylist(a,o),h=u.levels,d=u.sessionData;if(h.length){var f=h.map((function(t){return{id:t.attrs.AUDIO,audioCodec:t.audioCodec}})),g=h.map((function(t){return{id:t.attrs.SUBTITLES,textCodec:t.textCodec}})),v=k.parseMasterPlaylistMedia(a,o,"AUDIO",f),p=k.parseMasterPlaylistMedia(a,o,"SUBTITLES",g),m=k.parseMasterPlaylistMedia(a,o,"CLOSED-CAPTIONS");if(v.length)v.some((function(t){return!t.url}))||!h[0].audioCodec||h[0].attrs.AUDIO||(l.b.log("[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one"),v.unshift({type:"main",name:"main",default:!1,autoselect:!1,forced:!1,id:-1,attrs:new c({}),bitrate:0,url:""}));n.trigger(s.a.MANIFEST_LOADED,{levels:h,audioTracks:v,subtitles:p,captions:m,url:o,stats:e,networkDetails:r,sessionData:d})}else this.handleManifestParsingError(t,i,"no level found in manifest",r)},e.handleTrackOrLevelPlaylist=function(t,e,i,r){var n=this.hls,l=i.id,u=i.level,h=i.type,d=x(t,i),f=Object(a.a)(l)?l:0,g=Object(a.a)(u)?u:f,v=function(t){switch(t.type){case w.a.AUDIO_TRACK:return w.b.AUDIO;case w.a.SUBTITLE_TRACK:return w.b.SUBTITLE;default:return w.b.MAIN}}(i),p=k.parseLevelPlaylist(t.data,d,g,v,f);if(p.fragments.length){if(h===w.a.MANIFEST){var m={attrs:new c({}),bitrate:0,details:p,name:"",url:d};n.trigger(s.a.MANIFEST_LOADED,{levels:[m],audioTracks:[],url:d,stats:e,networkDetails:r,sessionData:null})}if(e.parsing.end=performance.now(),p.needSidxRanges){var y,T=null===(y=p.fragments[0].initSegment)||void 0===y?void 0:y.url;this.load({url:T,isSidxRequest:!0,type:h,level:u,levelDetails:p,id:l,groupId:null,rangeStart:0,rangeEnd:2048,responseType:"arraybuffer",deliveryDirectives:null})}else i.levelDetails=p,this.handlePlaylistLoaded(t,e,i,r)}else n.trigger(s.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.LEVEL_EMPTY_ERROR,fatal:!1,url:d,reason:"no fragments found in level",level:"number"==typeof i.level?i.level:void 0})},e.handleSidxRequest=function(t,e){var i=new Uint8Array(t.data),r=Object(u.c)(i,["sidx"])[0];if(r){var n=Object(u.k)(r);if(n){var a=n.references,s=e.levelDetails;a.forEach((function(t,e){var r=t.info,n=s.fragments[e];if(0===n.byteRange.length&&n.setByteRange(String(1+r.end-r.start)+"@"+String(r.start)),n.initSegment){var a=Object(u.c)(i,["moov"])[0],o=a?a.length:null;n.initSegment.setByteRange(String(o)+"@0")}}))}}},e.handleManifestParsingError=function(t,e,i,r){this.hls.trigger(s.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.MANIFEST_PARSING_ERROR,fatal:e.type===w.a.MANIFEST,url:t.url,reason:i,response:t,context:e,networkDetails:r})},e.handleNetworkError=function(t,e,i,r){void 0===i&&(i=!1),l.b.warn("[playlist-loader]: A network "+(i?"timeout":"error")+" occurred while loading "+t.type+" level: "+t.level+" id: "+t.id+' group-id: "'+t.groupId+'"');var n=o.a.UNKNOWN,a=!1,u=this.getInternalLoader(t);switch(t.type){case w.a.MANIFEST:n=i?o.a.MANIFEST_LOAD_TIMEOUT:o.a.MANIFEST_LOAD_ERROR,a=!0;break;case w.a.LEVEL:n=i?o.a.LEVEL_LOAD_TIMEOUT:o.a.LEVEL_LOAD_ERROR,a=!1;break;case w.a.AUDIO_TRACK:n=i?o.a.AUDIO_TRACK_LOAD_TIMEOUT:o.a.AUDIO_TRACK_LOAD_ERROR,a=!1;break;case w.a.SUBTITLE_TRACK:n=i?o.a.SUBTITLE_TRACK_LOAD_TIMEOUT:o.a.SUBTITLE_LOAD_ERROR,a=!1}u&&this.resetInternalLoader(t.type);var h={type:o.b.NETWORK_ERROR,details:n,fatal:a,url:t.url,loader:u,context:t,networkDetails:e};r&&(h.response=r),this.hls.trigger(s.a.ERROR,h)},e.handlePlaylistLoaded=function(t,e,i,r){var n=i.type,a=i.level,o=i.id,l=i.groupId,u=i.loader,h=i.levelDetails,d=i.deliveryDirectives;if(null!=h&&h.targetduration){if(u)switch(h.live&&(u.getCacheAge&&(h.ageHeader=u.getCacheAge()||0),u.getCacheAge&&!isNaN(h.ageHeader)||(h.ageHeader=0)),n){case w.a.MANIFEST:case w.a.LEVEL:this.hls.trigger(s.a.LEVEL_LOADED,{details:h,level:a||0,id:o||0,stats:e,networkDetails:r,deliveryDirectives:d});break;case w.a.AUDIO_TRACK:this.hls.trigger(s.a.AUDIO_TRACK_LOADED,{details:h,id:o||0,groupId:l||"",stats:e,networkDetails:r,deliveryDirectives:d});break;case w.a.SUBTITLE_TRACK:this.hls.trigger(s.a.SUBTITLE_TRACK_LOADED,{details:h,id:o||0,groupId:l||"",stats:e,networkDetails:r,deliveryDirectives:d})}}else this.handleManifestParsingError(t,i,"invalid target duration",r)},t}(),F=function(){function t(t){this.hls=void 0,this.loaders={},this.decryptkey=null,this.decrypturl=null,this.hls=t,this.registerListeners()}var e=t.prototype;return e.startLoad=function(t){},e.stopLoad=function(){this.destroyInternalLoaders()},e.registerListeners=function(){this.hls.on(s.a.KEY_LOADING,this.onKeyLoading,this)},e.unregisterListeners=function(){this.hls.off(s.a.KEY_LOADING,this.onKeyLoading)},e.destroyInternalLoaders=function(){for(var t in this.loaders){var e=this.loaders[t];e&&e.destroy()}this.loaders={}},e.destroy=function(){this.unregisterListeners(),this.destroyInternalLoaders()},e.onKeyLoading=function(t,e){var i=e.frag,r=i.type,n=this.loaders[r];if(i.decryptdata){var a=i.decryptdata.uri;if(a!==this.decrypturl||null===this.decryptkey){var o=this.hls.config;if(n&&(l.b.warn("abort previous key loader for type:"+r),n.abort()),!a)return void l.b.warn("key uri is falsy");var u=o.loader,h=i.loader=this.loaders[r]=new u(o);this.decrypturl=a,this.decryptkey=null;var d={url:a,frag:i,responseType:"arraybuffer"},c={timeout:o.fragLoadingTimeOut,maxRetry:0,retryDelay:o.fragLoadingRetryDelay,maxRetryDelay:o.fragLoadingMaxRetryTimeout,highWaterMark:0},f={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};h.load(d,c,f)}else this.decryptkey&&(i.decryptdata.key=this.decryptkey,this.hls.trigger(s.a.KEY_LOADED,{frag:i}))}else l.b.warn("Missing decryption data on fragment in onKeyLoading")},e.loadsuccess=function(t,e,i){var r=i.frag;r.decryptdata?(this.decryptkey=r.decryptdata.key=new Uint8Array(t.data),r.loader=null,delete this.loaders[r.type],this.hls.trigger(s.a.KEY_LOADED,{frag:r})):l.b.error("after key load, decryptdata unset")},e.loaderror=function(t,e){var i=e.frag,r=i.loader;r&&r.abort(),delete this.loaders[i.type],this.hls.trigger(s.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.KEY_LOAD_ERROR,fatal:!1,frag:i,response:t})},e.loadtimeout=function(t,e){var i=e.frag,r=i.loader;r&&r.abort(),delete this.loaders[i.type],this.hls.trigger(s.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.KEY_LOAD_TIMEOUT,fatal:!1,frag:i})},t}();function M(t,e){var i;try{i=new Event("addtrack")}catch(t){(i=document.createEvent("Event")).initEvent("addtrack",!1,!1)}i.track=t,e.dispatchEvent(i)}function N(t,e){var i=t.mode;if("disabled"===i&&(t.mode="hidden"),t.cues&&!t.cues.getCueById(e.id))try{if(t.addCue(e),!t.cues.getCueById(e.id))throw new Error("addCue is failed for: "+e)}catch(i){l.b.debug("[texttrack-utils]: "+i);var r=new self.TextTrackCue(e.startTime,e.endTime,e.text);r.id=e.id,t.addCue(r)}"disabled"===i&&(t.mode=i)}function U(t){var e=t.mode;if("disabled"===e&&(t.mode="hidden"),t.cues)for(var i=t.cues.length;i--;)t.removeCue(t.cues[i]);"disabled"===e&&(t.mode=e)}function B(t,e,i,r){var n=t.mode;if("disabled"===n&&(t.mode="hidden"),t.cues&&t.cues.length>0)for(var a=function(t,e,i){var r=[],n=function(t,e){if(et[i].endTime)return-1;var r=0,n=i;for(;r<=n;){var a=Math.floor((n+r)/2);if(et[a].startTime&&r-1)for(var a=n,s=t.length;a=e&&o.endTime<=i)r.push(o);else if(o.startTime>i)return r}return r}(t.cues,e,i),s=0;sn.startDate&&t.push(i),t}),[]).sort((function(t,e){return t.startDate.getTime()-e.startDate.getTime()}))[0];m&&(c=H(m.startDate,g),h=!0)}for(var y,T=Object.keys(n.attr),b=0;b.05&&this.forwardBufferLength>1){var u=Math.min(2,Math.max(1,a)),h=Math.round(2/(1+Math.exp(-.75*o-this.edgeStalled))*20)/20;t.playbackRate=Math.min(u,Math.max(1,h))}else 1!==t.playbackRate&&0!==t.playbackRate&&(t.playbackRate=1)}}}}},n.estimateLiveEdge=function(){var t=this.levelDetails;return null===t?null:t.edge+t.age},n.computeLatency=function(){var t=this.estimateLiveEdge();return null===t?null:t-this.currentTime},e=t,(i=[{key:"latency",get:function(){return this._latency||0}},{key:"maxLatency",get:function(){var t=this.config,e=this.levelDetails;return void 0!==t.liveMaxLatencyDuration?t.liveMaxLatencyDuration:e?t.liveMaxLatencyDurationCount*e.targetduration:0}},{key:"targetLatency",get:function(){var t=this.levelDetails;if(null===t)return null;var e=t.holdBack,i=t.partHoldBack,r=t.targetduration,n=this.config,a=n.liveSyncDuration,s=n.liveSyncDurationCount,o=n.lowLatencyMode,l=this.hls.userConfig,u=o&&i||e;(l.liveSyncDuration||l.liveSyncDurationCount||0===u)&&(u=void 0!==a?a:s*r);var h=r;return u+Math.min(1*this.stallCount,h)}},{key:"liveSyncPosition",get:function(){var t=this.estimateLiveEdge(),e=this.targetLatency,i=this.levelDetails;if(null===t||null===e||null===i)return null;var r=i.edge,n=t-e-this.edgeStalled,a=r-i.totalduration,s=r-(this.config.lowLatencyMode&&i.partTarget||i.targetduration);return Math.min(Math.max(a,n),s)}},{key:"drift",get:function(){var t=this.levelDetails;return null===t?1:t.drift}},{key:"edgeStalled",get:function(){var t=this.levelDetails;if(null===t)return 0;var e=3*(this.config.lowLatencyMode&&t.partTarget||t.targetduration);return Math.max(t.age-e,0)}},{key:"forwardBufferLength",get:function(){var t=this.media,e=this.levelDetails;if(!t||!e)return 0;var i=t.buffered.length;return(i?t.buffered.end(i-1):e.edge)-this.currentTime}}])&&W(e.prototype,i),r&&W(e,r),Object.defineProperty(e,"prototype",{writable:!1}),t}();function z(t,e){for(var i=0;it.sn?(n=i-t.start,r=t):(n=t.start-i,r=e),r.duration!==n&&(r.duration=n)}else if(e.sn>t.sn){t.cc===e.cc&&t.minEndPTS?e.start=t.start+(t.minEndPTS-t.start):e.start=t.start+t.duration}else e.start=Math.max(t.start-e.duration,0)}function et(t,e,i,r,n,s){r-i<=0&&(l.b.warn("Fragment should have a positive duration",e),r=i+e.duration,s=n+e.duration);var o=i,u=r,h=e.startPTS,d=e.endPTS;if(Object(a.a)(h)){var c=Math.abs(h-i);Object(a.a)(e.deltaPTS)?e.deltaPTS=Math.max(c,e.deltaPTS):e.deltaPTS=c,o=Math.max(i,h),i=Math.min(i,h),n=Math.min(n,e.startDTS),u=Math.min(r,d),r=Math.max(r,d),s=Math.max(s,e.endDTS)}e.duration=r-i;var f=i-e.start;e.appendedPTS=r,e.start=e.startPTS=i,e.maxStartPTS=o,e.startDTS=n,e.endPTS=r,e.minEndPTS=u,e.endDTS=s;var g,v=e.sn;if(!t||vt.endSN)return 0;var p=v-t.startSN,m=t.fragments;for(m[p]=e,g=p;g>0;g--)tt(m[g],m[g-1]);for(g=p;g=0;n--){var s=r[n].initSegment;if(s){i=s;break}}t.fragmentHint&&delete t.fragmentHint.endPTS;var o,u=0;(function(t,e,i){for(var r=e.skippedSegments,n=Math.max(t.startSN,e.startSN)-e.startSN,a=(t.fragmentHint?1:0)+(r?e.endSN:Math.min(t.endSN,e.endSN))-e.startSN,s=e.startSN-t.startSN,o=e.fragmentHint?e.fragments.concat(e.fragmentHint):e.fragments,l=t.fragmentHint?t.fragments.concat(t.fragmentHint):t.fragments,u=n;u<=a;u++){var h=l[s+u],d=o[u];r&&!d&&u=r.length||nt(e,r[i].start)}function nt(t,e){if(e){for(var i=t.fragments,r=t.skippedSegments;re.partTarget&&(l+=1)}if(Object(a.a)(o))return new X(o,Object(a.a)(l)?l:void 0,Y.No)}}},e.loadPlaylist=function(t){},e.shouldLoadTrack=function(t){return this.canLoad&&t&&!!t.url&&(!t.details||t.details.live)},e.playlistLoaded=function(t,e,i){var r=this,n=e.details,a=e.stats,s=a.loading.end?Math.max(0,self.performance.now()-a.loading.end):0;if(n.advancedDateTime=Date.now()-s,n.live||null!=i&&i.live){if(n.reloaded(i),i&&this.log("live playlist "+t+" "+(n.advanced?"REFRESHED "+n.lastPartSn+"-"+n.lastPartIndex:"MISSED")),i&&n.fragments.length>0&&it(i,n),!this.canLoad||!n.live)return;var o,l=void 0,u=void 0;if(n.canBlockReload&&n.endSN&&n.advanced){var h=this.hls.config.lowLatencyMode,d=n.lastPartSn,c=n.endSN,f=n.lastPartIndex,g=d===c;-1!==f?(l=g?c+1:d,u=g?h?0:f:f+1):l=c+1;var v=n.age,p=v+n.ageHeader,m=Math.min(p-n.partTarget,1.5*n.targetduration);if(m>0){if(i&&m>i.tuneInGoal)this.warn("CDN Tune-in goal increased from: "+i.tuneInGoal+" to: "+m+" with playlist age: "+n.age),m=0;else{var y=Math.floor(m/n.targetduration);if(l+=y,void 0!==u)u+=Math.round(m%n.targetduration/n.partTarget);this.log("CDN Tune-in age: "+n.ageHeader+"s last advanced "+v.toFixed(2)+"s goal: "+m+" skip sn "+y+" to part "+u)}n.tuneInGoal=m}if(o=this.getDeliveryDirectives(n,e.deliveryDirectives,l,u),h||!g)return void this.loadPlaylist(o)}else o=this.getDeliveryDirectives(n,e.deliveryDirectives,l,u);var T=function(t,e){var i,r=1e3*t.levelTargetDuration,n=r/2,a=t.age,s=a>0&&a<3*r,o=e.loading.end-e.loading.start,l=t.availabilityDelay;if(!1===t.updated)if(s){var u=333*t.misses;i=Math.max(Math.min(n,2*o),u),t.availabilityDelay=(t.availabilityDelay||0)+i}else i=n;else s?(l=Math.min(l||r/2,a),t.availabilityDelay=l,i=l+r-a):i=r-o;return Math.round(i)}(n,a);void 0!==l&&n.canBlockReload&&(T-=n.partTarget||1),this.log("reload live playlist "+t+" in "+Math.round(T)+" ms"),this.timer=self.setTimeout((function(){return r.loadPlaylist(o)}),T)}else this.clearTimer()},e.getDeliveryDirectives=function(t,e,i,r){var n=function(t,e){var i=t.canSkipUntil,r=t.canSkipDateRanges,n=t.endSN;return i&&(void 0!==e?e-n:0)-1&&null!==(e=t.context)&&void 0!==e&&e.deliveryDirectives)this.warn("retry playlist loading #"+this.retryCount+' after "'+t.details+'"'),this.loadPlaylist();else{var a=Math.min(Math.pow(2,this.retryCount)*r.levelLoadingRetryDelay,r.levelLoadingMaxRetryTimeout);this.timer=self.setTimeout((function(){return i.loadPlaylist()}),a),this.warn("retry playlist loading #"+this.retryCount+" in "+a+' ms after "'+t.details+'"')}else this.warn('cannot recover from error "'+t.details+'"'),this.clearTimer(),t.fatal=!0;return n},t}();function st(){return(st=Object.assign?Object.assign.bind():function(t){for(var e=1;e0){i=n[0].bitrate,n.sort((function(t,e){return t.bitrate-e.bitrate})),this._levels=n;for(var f=0;fthis.hls.config.fragLoadingMaxRetry&&(s=h)):s=h}break;case o.a.LEVEL_LOAD_ERROR:case o.a.LEVEL_LOAD_TIMEOUT:n&&(n.deliveryDirectives&&(u=!1),s=n.level),l=!0;break;case o.a.REMUX_ALLOC_ERROR:s=null!=(r=i.level)?r:this.currentLevelIndex,l=!0}void 0!==s&&this.recoverLevel(i,s,l,u)}}},u.recoverLevel=function(t,e,i,r){var n=t.details,a=this._levels[e];if(a.loadError++,i){if(!this.retryLoadingOrFail(t))return void(this.currentLevelIndex=-1);t.levelRetry=!0}if(r){var s=a.url.length;if(s>1&&a.loadError-1&&this.currentLevelIndex!==o&&(this.warn(n+": switch to "+o),t.levelRetry=!0,this.hls.nextAutoLevel=o)}}},u.redundantFailover=function(t){var e=this._levels[t],i=e.url.length;if(i>1){var r=(e.urlId+1)%i;this.warn("Switching to redundant URL-id "+r),this._levels.forEach((function(t){t.urlId=r})),this.level=t}},u.onFragLoaded=function(t,e){var i=e.frag;if(void 0!==i&&i.type===w.b.MAIN){var r=this._levels[i.level];void 0!==r&&(r.fragmentError=0,r.loadError=0)}},u.onLevelLoaded=function(t,e){var i,r,n=e.level,a=e.details,s=this._levels[n];if(!s)return this.warn("Invalid level index "+n),void(null!==(r=e.deliveryDirectives)&&void 0!==r&&r.skip&&(a.deltaUpdateFailed=!0));n===this.currentLevelIndex?(0===s.fragmentError&&(s.loadError=0,this.retryCount=0),this.playlistLoaded(n,e,s.details)):null!==(i=e.deliveryDirectives)&&void 0!==i&&i.skip&&(a.deltaUpdateFailed=!0)},u.onAudioTrackSwitched=function(t,e){var i=this.hls.levels[this.currentLevelIndex];if(i&&i.audioGroupIds){for(var r=-1,n=this.hls.audioTracks[e.id].groupId,a=0;a0){var r=i.urlId,n=i.url[r];if(t)try{n=t.addDirectives(n)}catch(t){this.warn("Could not construct new URL with HLS Delivery Directives: "+t)}this.log("Attempt loading level index "+e+(t?" at sn "+t.msn+" part "+t.part:"")+" with URL-id "+r+" "+n),this.clearTimer(),this.hls.trigger(s.a.LEVEL_LOADING,{url:n,level:e,id:r,deliveryDirectives:t||null})}},u.removeLevel=function(t,e){var i=function(t,i){return i!==e},r=this._levels.filter((function(r,n){return n!==t||r.url.length>1&&void 0!==e&&(r.url=r.url.filter(i),r.audioGroupIds&&(r.audioGroupIds=r.audioGroupIds.filter(i)),r.textGroupIds&&(r.textGroupIds=r.textGroupIds.filter(i)),r.urlId=0,!0)})).map((function(t,e){var i=t.details;return null!=i&&i.fragments&&i.fragments.forEach((function(t){t.level=e})),t}));this._levels=r,this.hls.trigger(s.a.LEVELS_UPDATED,{levels:r})},n=r,(a=[{key:"levels",get:function(){return 0===this._levels.length?null:this._levels}},{key:"level",get:function(){return this.currentLevelIndex},set:function(t){var e,i=this._levels;if(0!==i.length&&(this.currentLevelIndex!==t||null===(e=i[t])||void 0===e||!e.details)){if(t<0||t>=i.length){var r=t<0;if(this.hls.trigger(s.a.ERROR,{type:o.b.OTHER_ERROR,details:o.a.LEVEL_SWITCH_ERROR,level:t,fatal:r,reason:"invalid level idx"}),r)return;t=Math.min(t,i.length-1)}this.clearTimer();var n=this.currentLevelIndex,a=i[n],l=i[t];this.log("switching to level "+t+" from "+n),this.currentLevelIndex=t;var u=st({},l,{level:t,maxBitrate:l.maxBitrate,uri:l.uri,urlId:l.urlId});delete u._urlId,this.hls.trigger(s.a.LEVEL_SWITCHING,u);var h=l.details;if(!h||h.live){var d=this.switchParams(l.uri,null==a?void 0:a.details);this.loadPlaylist(d)}}}},{key:"manualLevel",get:function(){return this.manualLevelIndex},set:function(t){this.manualLevelIndex=t,void 0===this._startLevel&&(this._startLevel=t),-1!==t&&(this.level=t)}},{key:"firstLevel",get:function(){return this._firstLevel},set:function(t){this._firstLevel=t}},{key:"startLevel",get:function(){if(void 0===this._startLevel){var t=this.hls.config.startLevel;return void 0!==t?t:this._firstLevel}return this._startLevel},set:function(t){this._startLevel=t}},{key:"nextLoadLevel",get:function(){return-1!==this.manualLevelIndex?this.manualLevelIndex:this.hls.nextAutoLevel},set:function(t){this.level=t,-1===this.manualLevelIndex&&(this.hls.nextAutoLevel=t)}}])&&ot(n.prototype,a),l&&ot(n,l),Object.defineProperty(n,"prototype",{writable:!1}),r}(at);!function(t){t.NOT_LOADED="NOT_LOADED",t.APPENDING="APPENDING",t.PARTIAL="PARTIAL",t.OK="OK"}(ut||(ut={}));var ct=function(){function t(t){this.activeFragment=null,this.activeParts=null,this.fragments=Object.create(null),this.timeRanges=Object.create(null),this.bufferPadding=.2,this.hls=void 0,this.hls=t,this._registerListeners()}var e=t.prototype;return e._registerListeners=function(){var t=this.hls;t.on(s.a.BUFFER_APPENDED,this.onBufferAppended,this),t.on(s.a.FRAG_BUFFERED,this.onFragBuffered,this),t.on(s.a.FRAG_LOADED,this.onFragLoaded,this)},e._unregisterListeners=function(){var t=this.hls;t.off(s.a.BUFFER_APPENDED,this.onBufferAppended,this),t.off(s.a.FRAG_BUFFERED,this.onFragBuffered,this),t.off(s.a.FRAG_LOADED,this.onFragLoaded,this)},e.destroy=function(){this._unregisterListeners(),this.fragments=this.timeRanges=null},e.getAppendedFrag=function(t,e){if(e===w.b.MAIN){var i=this.activeFragment,r=this.activeParts;if(!i)return null;if(r)for(var n=r.length;n--;){var a=r[n],s=a?a.end:i.appendedPTS;if(a.start<=t&&void 0!==s&&t<=s)return n>9&&(this.activeParts=r.slice(n-9)),a}else if(i.start<=t&&void 0!==i.appendedPTS&&t<=i.appendedPTS)return i}return this.getBufferedFrag(t,e)},e.getBufferedFrag=function(t,e){for(var i=this.fragments,r=Object.keys(i),n=r.length;n--;){var a=i[r[n]];if((null==a?void 0:a.body.type)===e&&a.buffered){var s=a.body;if(s.start<=t&&t<=s.end)return s}}return null},e.detectEvictedFragments=function(t,e,i){var r=this;Object.keys(this.fragments).forEach((function(n){var a=r.fragments[n];if(a)if(a.buffered){var s=a.range[t];s&&s.time.some((function(t){var i=!r.isTimeBuffered(t.startPTS,t.endPTS,e);return i&&r.removeFragment(a.body),i}))}else a.body.type===i&&r.removeFragment(a.body)}))},e.detectPartialFragments=function(t){var e=this,i=this.timeRanges,r=t.frag,n=t.part;if(i&&"initSegment"!==r.sn){var a=gt(r),s=this.fragments[a];s&&(Object.keys(i).forEach((function(t){var a=r.elementaryStreams[t];if(a){var o=i[t],l=null!==n||!0===a.partial;s.range[t]=e.getBufferedTimes(r,n,l,o)}})),s.loaded=null,Object.keys(s.range).length?s.buffered=!0:this.removeFragment(s.body))}},e.fragBuffered=function(t){var e=gt(t),i=this.fragments[e];i&&(i.loaded=null,i.buffered=!0)},e.getBufferedTimes=function(t,e,i,r){for(var n={time:[],partial:i},a=e?e.start:t.start,s=e?e.end:t.end,o=t.minEndPTS||s,l=t.maxStartPTS||a,u=0;u=h&&o<=d){n.time.push({startPTS:Math.max(a,r.start(u)),endPTS:Math.min(s,r.end(u))});break}if(ah)n.partial=!0,n.time.push({startPTS:Math.max(a,r.start(u)),endPTS:Math.min(s,r.end(u))});else if(s<=h)break}return n},e.getPartialFragment=function(t){var e,i,r,n=null,a=0,s=this.bufferPadding,o=this.fragments;return Object.keys(o).forEach((function(l){var u=o[l];u&&ft(u)&&(i=u.body.start-s,r=u.body.end+s,t>=i&&t<=r&&(e=Math.min(t-i,r-t),a<=e&&(n=u.body,a=e)))})),n},e.getState=function(t){var e=gt(t),i=this.fragments[e];return i?i.buffered?ft(i)?ut.PARTIAL:ut.OK:ut.APPENDING:ut.NOT_LOADED},e.isTimeBuffered=function(t,e,i){for(var r,n,a=0;a=r&&e<=n)return!0;if(e<=r)return!1}return!1},e.onFragLoaded=function(t,e){var i=e.frag,r=e.part;if("initSegment"!==i.sn&&!i.bitrateTest&&!r){var n=gt(i);this.fragments[n]={body:i,loaded:e,buffered:!1,range:Object.create(null)}}},e.onBufferAppended=function(t,e){var i=this,r=e.frag,n=e.part,a=e.timeRanges;if(r.type===w.b.MAIN)if(this.activeFragment=r,n){var s=this.activeParts;s||(this.activeParts=s=[]),s.push(n)}else this.activeParts=null;this.timeRanges=a,Object.keys(a).forEach((function(t){var e=a[t];if(i.detectEvictedFragments(t,e),!n)for(var s=0;st&&r.removeFragment(s)}}))},e.removeFragment=function(t){var e=gt(t);t.stats.loaded=0,t.clearElementaryStreamInfo(),delete this.fragments[e]},e.removeAllFragments=function(){this.fragments=Object.create(null),this.activeFragment=null,this.activeParts=null},t}();function ft(t){var e,i;return t.buffered&&((null===(e=t.range.video)||void 0===e?void 0:e.partial)||(null===(i=t.range.audio)||void 0===i?void 0:i.partial))}function gt(t){return t.type+"_"+t.level+"_"+t.urlId+"_"+t.sn}var vt=function(){function t(){this._boundTick=void 0,this._tickTimer=null,this._tickInterval=null,this._tickCallCount=0,this._boundTick=this.tick.bind(this)}var e=t.prototype;return e.destroy=function(){this.onHandlerDestroying(),this.onHandlerDestroyed()},e.onHandlerDestroying=function(){this.clearNextTick(),this.clearInterval()},e.onHandlerDestroyed=function(){},e.hasInterval=function(){return!!this._tickInterval},e.hasNextTick=function(){return!!this._tickTimer},e.setInterval=function(t){return!this._tickInterval&&(this._tickInterval=self.setInterval(this._boundTick,t),!0)},e.clearInterval=function(){return!!this._tickInterval&&(self.clearInterval(this._tickInterval),this._tickInterval=null,!0)},e.clearNextTick=function(){return!!this._tickTimer&&(self.clearTimeout(this._tickTimer),this._tickTimer=null,!0)},e.tick=function(){this._tickCallCount++,1===this._tickCallCount&&(this.doTick(),this._tickCallCount>1&&this.tickImmediate(),this._tickCallCount=0)},e.tickImmediate=function(){this.clearNextTick(),this._tickTimer=self.setTimeout(this._boundTick,0)},e.doTick=function(){},t}(),pt={length:0,start:function(){return 0},end:function(){return 0}},mt=function(){function t(){}return t.isBuffered=function(e,i){try{if(e)for(var r=t.getBuffered(e),n=0;n=r.start(n)&&i<=r.end(n))return!0}catch(t){}return!1},t.bufferInfo=function(e,i,r){try{if(e){var n,a=t.getBuffered(e),s=[];for(n=0;ns&&(r[a-1].end=t[n].end):r.push(t[n])}else r.push(t[n])}else r=t;for(var o,l=0,u=e,h=e,d=0;d=c&&ei.startCC||t&&t.cc0)i=n+1;else{if(!(s<0))return a;r=n-1}}return null}};function Dt(t,e,i,r){void 0===i&&(i=0),void 0===r&&(r=0);var n=null;if(t?n=e[t.sn-e[0].sn+1]||null:0===i&&0===e[0].start&&(n=e[0]),n&&0===Rt(i,r,n))return n;var a=At.search(e,Rt.bind(null,i,r));return a||n}function Rt(t,e,i){void 0===t&&(t=0),void 0===e&&(e=0);var r=Math.min(e,i.duration+(i.deltaPTS?i.deltaPTS:0));return i.start+i.duration-r<=t?1:i.start-r>t&&i.start?-1:0}function kt(t,e,i){var r=1e3*Math.min(e,i.duration+(i.deltaPTS?i.deltaPTS:0));return(i.endProgramDateTime||0)-r>t}function _t(t){var e="function"==typeof Map?new Map:void 0;return(_t=function(t){if(null===t||(i=t,-1===Function.toString.call(i).indexOf("[native code]")))return t;var i;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,r)}function r(){return It(t,arguments,wt(this).constructor)}return r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),Ct(r,t)})(t)}function It(t,e,i){return(It=Ot()?Reflect.construct.bind():function(t,e,i){var r=[null];r.push.apply(r,e);var n=new(Function.bind.apply(t,r));return i&&Ct(n,i.prototype),n}).apply(null,arguments)}function Ot(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function Ct(t,e){return(Ct=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}function wt(t){return(wt=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}var xt=Math.pow(2,17),Pt=function(){function t(t){this.config=void 0,this.loader=null,this.partLoadTimeout=-1,this.config=t}var e=t.prototype;return e.destroy=function(){this.loader&&(this.loader.destroy(),this.loader=null)},e.abort=function(){this.loader&&this.loader.abort()},e.load=function(t,e){var i=this,r=t.url;if(!r)return Promise.reject(new Mt({type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,networkDetails:null},"Fragment does not have a "+(r?"part list":"url")));this.abort();var n=this.config,a=n.fLoader,s=n.loader;return new Promise((function(r,l){i.loader&&i.loader.destroy();var u=i.loader=t.loader=a?new a(n):new s(n),h=Ft(t),d={timeout:n.fragLoadingTimeOut,maxRetry:0,retryDelay:0,maxRetryDelay:n.fragLoadingMaxRetryTimeout,highWaterMark:"initSegment"===t.sn?1/0:xt};t.stats=u.stats,u.load(h,d,{onSuccess:function(e,n,a,s){i.resetLoader(t,u),r({frag:t,part:null,payload:e.data,networkDetails:s})},onError:function(e,r,n){i.resetLoader(t,u),l(new Mt({type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,response:e,networkDetails:n}))},onAbort:function(e,r,n){i.resetLoader(t,u),l(new Mt({type:o.b.NETWORK_ERROR,details:o.a.INTERNAL_ABORTED,fatal:!1,frag:t,networkDetails:n}))},onTimeout:function(e,r,n){i.resetLoader(t,u),l(new Mt({type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_TIMEOUT,fatal:!1,frag:t,networkDetails:n}))},onProgress:function(i,r,n,a){e&&e({frag:t,part:null,payload:n,networkDetails:a})}})}))},e.loadPart=function(t,e,i){var r=this;this.abort();var n=this.config,a=n.fLoader,s=n.loader;return new Promise((function(l,u){r.loader&&r.loader.destroy();var h=r.loader=t.loader=a?new a(n):new s(n),d=Ft(t,e),c={timeout:n.fragLoadingTimeOut,maxRetry:0,retryDelay:0,maxRetryDelay:n.fragLoadingMaxRetryTimeout,highWaterMark:xt};e.stats=h.stats,h.load(d,c,{onSuccess:function(n,a,s,o){r.resetLoader(t,h),r.updateStatsFromPart(t,e);var u={frag:t,part:e,payload:n.data,networkDetails:o};i(u),l(u)},onError:function(i,n,a){r.resetLoader(t,h),u(new Mt({type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_ERROR,fatal:!1,frag:t,part:e,response:i,networkDetails:a}))},onAbort:function(i,n,a){t.stats.aborted=e.stats.aborted,r.resetLoader(t,h),u(new Mt({type:o.b.NETWORK_ERROR,details:o.a.INTERNAL_ABORTED,fatal:!1,frag:t,part:e,networkDetails:a}))},onTimeout:function(i,n,a){r.resetLoader(t,h),u(new Mt({type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_TIMEOUT,fatal:!1,frag:t,part:e,networkDetails:a}))}})}))},e.updateStatsFromPart=function(t,e){var i=t.stats,r=e.stats,n=r.total;if(i.loaded+=r.loaded,n){var a=Math.round(t.duration/e.duration),s=Math.min(Math.round(i.loaded/n),a),o=(a-s)*Math.round(i.loaded/s);i.total=i.loaded+o}else i.total=Math.max(i.loaded,i.total);var l=i.loading,u=r.loading;l.start?l.first+=u.first-u.start:(l.start=u.start,l.first=u.first),l.end=u.end},e.resetLoader=function(t,e){t.loader=null,this.loader===e&&(self.clearTimeout(this.partLoadTimeout),this.loader=null),e.destroy()},t}();function Ft(t,e){void 0===e&&(e=null);var i=e||t,r={frag:t,part:e,responseType:"arraybuffer",url:i.url,headers:{},rangeStart:0,rangeEnd:0},n=i.byteRangeStartOffset,s=i.byteRangeEndOffset;return Object(a.a)(n)&&Object(a.a)(s)&&(r.rangeStart=n,r.rangeEnd=s),r}var Mt=function(t){var e,i;function r(e){for(var i,r=arguments.length,n=new Array(r>1?r-1:0),a=1;a=e.endSN&&!t.nextStart){var n=e.partList;if(null!=n&&n.length){var a=n[n.length-1];return mt.isBuffered(this.media,a.start+a.duration/2)}var s=r.getState(i);return s===ut.PARTIAL||s===ut.OK}return!1},c.onMediaAttached=function(t,e){var i=this.media=this.mediaBuffer=e.media;this.onvseeking=this.onMediaSeeking.bind(this),this.onvended=this.onMediaEnded.bind(this),i.addEventListener("seeking",this.onvseeking),i.addEventListener("ended",this.onvended);var r=this.config;this.levels&&r.autoStartLoad&&this.state===Kt&&this.startLoad(r.startPosition)},c.onMediaDetaching=function(){var t=this.media;null!=t&&t.ended&&(this.log("MSE detaching and video ended, reset startPosition"),this.startPosition=this.lastCurrentTime=0),t&&this.onvseeking&&this.onvended&&(t.removeEventListener("seeking",this.onvseeking),t.removeEventListener("ended",this.onvended),this.onvseeking=this.onvended=null),this.media=this.mediaBuffer=null,this.loadedmetadata=!1,this.fragmentTracker.removeAllFragments(),this.stopLoad()},c.onMediaSeeking=function(){var t=this.config,e=this.fragCurrent,i=this.media,r=this.mediaBuffer,n=this.state,s=i?i.currentTime:0,o=mt.bufferInfo(r||i,s,t.maxBufferHole);if(this.log("media seeking to "+(Object(a.a)(s)?s.toFixed(3):s)+", state: "+n),n===Qt)this.resetLoadingState();else if(e&&!o.len){var l=t.maxFragLookUpTolerance,u=e.start-l,h=s>e.start+e.duration+l;(s0&&a&&a.key&&a.iv&&"AES-128"===a.method){var o=self.performance.now();return e.decrypter.webCryptoDecrypt(new Uint8Array(n),a.key.buffer,a.iv.buffer).then((function(e){var n=self.performance.now();return r.trigger(s.a.FRAG_DECRYPTED,{frag:t,payload:e,stats:{tstart:o,tdecrypt:n}}),i.payload=e,i}))}return i})).then((function(i){var r=e.fragCurrent,n=e.hls,a=e.levels;if(!a)throw new Error("init load aborted, missing levels");a[t.level].details;var o=t.stats;e.state=Ht,e.fragLoadError=0,t.data=new Uint8Array(i.payload),o.parsing.start=o.buffering.start=self.performance.now(),o.parsing.end=o.buffering.end=self.performance.now(),i.frag===r&&n.trigger(s.a.FRAG_BUFFERED,{stats:o,frag:r,part:null,id:t.type}),e.tick()})).catch((function(i){e.state!==Kt&&e.state!==$t&&(e.warn(i),e.resetFragmentLoading(t))}))},c.fragContextChanged=function(t){var e=this.fragCurrent;return!t||!e||t.level!==e.level||t.sn!==e.sn||t.urlId!==e.urlId},c.fragBufferedComplete=function(t,e){var i=this.mediaBuffer?this.mediaBuffer:this.media;this.log("Buffered "+t.type+" sn: "+t.sn+(e?" part: "+e.index:"")+" of "+("[stream-controller]"===this.logPrefix?"level":"track")+" "+t.level+" "+(i?Ut.toString(mt.getBuffered(i)):"(detached)")),this.state=Ht,i&&(!this.loadedmetadata&&i.buffered.length&&this.fragCurrent===this.fragPrevious&&(this.loadedmetadata=!0,this.seekToStartPos()),this.tick())},c.seekToStartPos=function(){},c._handleFragmentLoadComplete=function(t){var e=this.transmuxer;if(e){var i=t.frag,r=t.part,n=t.partsLoaded,a=!n||0===n.length||n.some((function(t){return!t})),s=new yt(i.level,i.sn,i.stats.chunkCount+1,0,r?r.index:-1,!a);e.flush(s)}},c._handleFragmentLoadProgress=function(t){},c._doFragLoad=function(t,e,i,r){var n=this;if(void 0===i&&(i=null),!this.levels)throw new Error("frag load aborted, missing levels");if(i=Math.max(t.start,i||0),this.config.lowLatencyMode&&e){var o=e.partList;if(o&&r){i>t.end&&e.fragmentHint&&(t=e.fragmentHint);var l=this.getNextPart(o,t,i);if(l>-1){var u=o[l];return this.log("Loading part sn: "+t.sn+" p: "+u.index+" cc: "+t.cc+" of playlist ["+e.startSN+"-"+e.endSN+"] parts [0-"+l+"-"+(o.length-1)+"] "+("[stream-controller]"===this.logPrefix?"level":"track")+": "+t.level+", target: "+parseFloat(i.toFixed(3))),this.nextLoadPosition=u.start+u.duration,this.state=Wt,this.hls.trigger(s.a.FRAG_LOADING,{frag:t,part:o[l],targetBufferTime:i}),this.doFragPartsLoad(t,o,l,r).catch((function(t){return n.handleFragLoadError(t)}))}if(!t.url||this.loadedEndOfParts(o,i))return Promise.resolve(null)}}return this.log("Loading fragment "+t.sn+" cc: "+t.cc+" "+(e?"of ["+e.startSN+"-"+e.endSN+"] ":"")+("[stream-controller]"===this.logPrefix?"level":"track")+": "+t.level+", target: "+parseFloat(i.toFixed(3))),Object(a.a)(t.sn)&&!this.bitrateTest&&(this.nextLoadPosition=t.start+t.duration),this.state=Wt,this.hls.trigger(s.a.FRAG_LOADING,{frag:t,targetBufferTime:i}),this.fragmentLoader.load(t,r).catch((function(t){return n.handleFragLoadError(t)}))},c.doFragPartsLoad=function(t,e,i,r){var n=this;return new Promise((function(a,o){var l=[];!function i(u){var h=e[u];n.fragmentLoader.loadPart(t,h,r).then((function(r){l[h.index]=r;var o=r.part;n.hls.trigger(s.a.FRAG_LOADED,r);var d=e[u+1];if(!d||d.fragment!==t)return a({frag:t,part:o,partsLoaded:l});i(u+1)})).catch(o)}(i)}))},c.handleFragLoadError=function(t){var e=t.data;return e&&e.details===o.a.INTERNAL_ABORTED?this.handleFragLoadAborted(e.frag,e.part):this.hls.trigger(s.a.ERROR,e),null},c._handleTransmuxerFlush=function(t){var e=this.getCurrentContext(t);if(e&&this.state===zt){var i=e.frag,r=e.part,n=e.level,a=self.performance.now();i.stats.parsing.end=a,r&&(r.stats.parsing.end=a),this.updateLevelTiming(i,r,n,t.partial)}else this.fragCurrent||(this.state=Ht)},c.getCurrentContext=function(t){var e=this.levels,i=t.level,r=t.sn,n=t.part;if(!e||!e[i])return this.warn("Levels object was unset while buffering fragment "+r+" of level "+i+". The current chunk will not be buffered."),null;var a=e[i],s=n>-1?function(t,e,i){if(!t||!t.details)return null;var r=t.details.partList;if(r)for(var n=r.length;n--;){var a=r[n];if(a.index===i&&a.fragment.sn===e)return a}return null}(a,r,n):null,o=s?s.fragment:function(t,e,i){if(!t||!t.details)return null;var r=t.details,n=r.fragments[e-r.startSN];return n||((n=r.fragmentHint)&&n.sn===e?n:ea&&this.flushMainBuffer(s,t.start)}else this.flushMainBuffer(0,t.start)},c.getFwdBufferInfo=function(t,e){var i=this.config,r=this.getLoadPosition();if(!Object(a.a)(r))return null;var n=mt.bufferInfo(t,r,i.maxBufferHole);if(0===n.len&&void 0!==n.nextStart){var s=this.fragmentTracker.getBufferedFrag(r,e);if(s&&n.nextStart=i&&(e.maxMaxBufferLength/=2,this.warn("Reduce max buffer length to "+e.maxMaxBufferLength+"s"),!0)},c.getNextFragment=function(t,e){var i=e.fragments,r=i.length;if(!r)return null;var n,a=this.config,s=i[0].start;if(e.live){var o=a.initialLiveManifestSize;if(r-1&&ii.start&&i.loaded},c.getInitialLiveFragment=function(t,e){var i=this.fragPrevious,r=null;if(i){if(t.hasProgramDateTime&&(this.log("Live playlist, switching playlist, load frag with same PDT: "+i.programDateTime),r=function(t,e,i){if(null===e||!Array.isArray(t)||!t.length||!Object(a.a)(e))return null;if(e<(t[0].programDateTime||0))return null;if(e>=(t[t.length-1].endProgramDateTime||0))return null;i=i||0;for(var r=0;r=t.startSN&&n<=t.endSN){var s=e[n-t.startSN];i.cc===s.cc&&(r=s,this.log("Live playlist, switching playlist, load frag with next SN: "+r.sn))}r||(r=function(t,e){return At.search(t,(function(t){return t.cce?-1:0}))}(e,i.cc))&&this.log("Live playlist, switching playlist, load frag with same CC: "+r.sn)}}else{var o=this.hls.liveSyncPosition;null!==o&&(r=this.getFragmentAtPosition(o,this.bitrateTest?t.fragmentEnd:t.edge,t))}return r},c.getFragmentAtPosition=function(t,e,i){var r,n=this.config,a=this.fragPrevious,s=i.fragments,o=i.endSN,l=i.fragmentHint,u=n.maxFragLookUpTolerance,h=!!(n.lowLatencyMode&&i.partList&&l);(h&&l&&!this.bitrateTest&&(s=s.concat(l),o=l.sn),te-u?0:u):r=s[s.length-1];if(r){var d=r.sn-i.startSN;if(a&&r.sn===a.sn&&!h)if(a&&r.level===a.level){var c=s[d+1];r.sn=a-e.maxFragLookUpTolerance&&n<=s;if(null!==r&&i.duration>r&&(n"+t.startSN+" prev-sn: "+(n?n.sn:"na")+" fragments: "+o),d}return l},c.waitForCdnTuneIn=function(t){return t.live&&t.canBlockReload&&t.partTarget&&t.tuneInGoal>Math.max(t.partHoldBack,3*t.partTarget)},c.setStartPosition=function(t,e){var i=this.startPosition;if(i"+t))}}])&&Bt(n.prototype,h),d&&Bt(n,d),Object.defineProperty(n,"prototype",{writable:!1}),r}(vt);function ee(){return self.MediaSource||self.WebKitMediaSource}function ie(){return self.SourceBuffer||self.WebKitSourceBuffer}var re=i(18),ne=i(10),ae=i(15),se=ee()||{isTypeSupported:function(){return!1}},oe=function(){function t(t,e,i,r){var n=this;this.hls=void 0,this.id=void 0,this.observer=void 0,this.frag=null,this.part=null,this.worker=void 0,this.onwmsg=void 0,this.transmuxer=null,this.onTransmuxComplete=void 0,this.onFlush=void 0,this.hls=t,this.id=e,this.onTransmuxComplete=i,this.onFlush=r;var a=t.config,u=function(e,i){(i=i||{}).frag=n.frag,i.id=n.id,t.trigger(e,i)};this.observer=new ae.EventEmitter,this.observer.on(s.a.FRAG_DECRYPTED,u),this.observer.on(s.a.ERROR,u);var h={mp4:se.isTypeSupported("video/mp4"),mpeg:se.isTypeSupported("audio/mpeg"),mp3:se.isTypeSupported('audio/mp4; codecs="mp3"')},d=navigator.vendor;if(a.enableWorker&&"undefined"!=typeof Worker){var c;l.b.log("demuxing in webworker");try{c=this.worker=re(19),this.onwmsg=this.onWorkerMessage.bind(this),c.addEventListener("message",this.onwmsg),c.onerror=function(e){t.trigger(s.a.ERROR,{type:o.b.OTHER_ERROR,details:o.a.INTERNAL_EXCEPTION,fatal:!0,event:"demuxerWorker",error:new Error(e.message+" ("+e.filename+":"+e.lineno+")")})},c.postMessage({cmd:"init",typeSupported:h,vendor:d,id:e,config:JSON.stringify(a)})}catch(t){l.b.warn("Error in worker:",t),l.b.error("Error while initializing DemuxerWorker, fallback to inline"),c&&self.URL.revokeObjectURL(c.objectURL),this.transmuxer=new ne.c(this.observer,h,a,d,e),this.worker=null}}else this.transmuxer=new ne.c(this.observer,h,a,d,e)}var e=t.prototype;return e.destroy=function(){var t=this.worker;if(t)t.removeEventListener("message",this.onwmsg),t.terminate(),this.worker=null,this.onwmsg=void 0;else{var e=this.transmuxer;e&&(e.destroy(),this.transmuxer=null)}var i=this.observer;i&&i.removeAllListeners(),this.frag=null,this.observer=null,this.hls=null},e.push=function(t,e,i,r,n,a,s,o,u,h){var d,c,f=this;u.transmuxing.start=self.performance.now();var g=this.transmuxer,v=this.worker,p=a?a.start:n.start,m=n.decryptdata,y=this.frag,T=!(y&&n.cc===y.cc),b=!(y&&u.level===y.level),E=y?u.sn-y.sn:-1,S=this.part?u.part-this.part.index:-1,L=0===E&&u.id>1&&u.id===(null==y?void 0:y.stats.chunkCount),A=!b&&(1===E||0===E&&(1===S||L&&S<=0)),D=self.performance.now();(b||E||0===n.stats.parsing.start)&&(n.stats.parsing.start=D),!a||!S&&A||(a.stats.parsing.start=D);var R=!(y&&(null===(d=n.initSegment)||void 0===d?void 0:d.url)===(null===(c=y.initSegment)||void 0===c?void 0:c.url)),k=new ne.b(T,A,o,b,p,R);if(!A||T||R){l.b.log("[transmuxer-interface, "+n.type+"]: Starting new transmux session for sn: "+u.sn+" p: "+u.part+" level: "+u.level+" id: "+u.id+"\n discontinuity: "+T+"\n trackSwitch: "+b+"\n contiguous: "+A+"\n accurateTimeOffset: "+o+"\n timeOffset: "+p+"\n initSegmentChange: "+R);var _=new ne.a(i,r,e,s,h);this.configureTransmuxer(_)}if(this.frag=n,this.part=a,v)v.postMessage({cmd:"demux",data:t,decryptdata:m,chunkMeta:u,state:k},t instanceof ArrayBuffer?[t]:[]);else if(g){var I=g.push(t,m,u,k);Object(ne.d)(I)?I.then((function(t){f.handleTransmuxComplete(t)})):this.handleTransmuxComplete(I)}},e.flush=function(t){var e=this;t.transmuxing.start=self.performance.now();var i=this.transmuxer,r=this.worker;if(r)r.postMessage({cmd:"flush",chunkMeta:t});else if(i){var n=i.flush(t);Object(ne.d)(n)?n.then((function(i){e.handleFlushResult(i,t)})):this.handleFlushResult(n,t)}},e.handleFlushResult=function(t,e){var i=this;t.forEach((function(t){i.handleTransmuxComplete(t)})),this.onFlush(e)},e.onWorkerMessage=function(t){var e=t.data,i=this.hls;switch(e.event){case"init":self.URL.revokeObjectURL(this.worker.objectURL);break;case"transmuxComplete":this.handleTransmuxComplete(e.data);break;case"flush":this.onFlush(e.data);break;case"workerLog":l.b[e.data.logType]&&l.b[e.data.logType](e.data.message);break;default:e.data=e.data||{},e.data.frag=this.frag,e.data.id=this.id,i.trigger(e.event,e.data)}},e.configureTransmuxer=function(t){var e=this.worker,i=this.transmuxer;e?e.postMessage({cmd:"configure",config:t}):i&&i.configure(t)},e.handleTransmuxComplete=function(t){t.chunkMeta.transmuxing.end=self.performance.now(),this.onTransmuxComplete(t)},t}(),le=function(){function t(t,e,i,r){this.config=void 0,this.media=null,this.fragmentTracker=void 0,this.hls=void 0,this.nudgeRetry=0,this.stallReported=!1,this.stalled=null,this.moved=!1,this.seeking=!1,this.config=t,this.media=e,this.fragmentTracker=i,this.hls=r}var e=t.prototype;return e.destroy=function(){this.media=null,this.hls=this.fragmentTracker=null},e.poll=function(t,e){var i=this.config,r=this.media,n=this.stalled;if(null!==r){var a=r.currentTime,s=r.seeking,o=this.seeking&&!s,u=!this.seeking&&s;if(this.seeking=s,a===t){if((u||o)&&(this.stalled=null),!(r.paused&&!s||r.ended||0===r.playbackRate)&&mt.getBuffered(r).length){var h=mt.bufferInfo(r,a,0),d=h.len>0,c=h.nextStart||0;if(d||c){if(s){var f=h.len>2,g=!c||e&&e.start<=a||c-a>2&&!this.fragmentTracker.getPartialFragment(a);if(f||g)return;this.moved=!1}if(!this.moved&&null!==this.stalled){var v,p=Math.max(c,h.start||0)-a,m=this.hls.levels?this.hls.levels[this.hls.currentLevel]:null,y=(null==m||null===(v=m.details)||void 0===v?void 0:v.live)?2*m.details.targetduration:2;if(p>0&&p<=y)return void this._trySkipBufferHole(null)}var T=self.performance.now();if(null!==n){var b=T-n;if(s||!(b>=250)||(this._reportStall(h),this.media)){var E=mt.bufferInfo(r,a,i.maxBufferHole);this._tryFixBufferStall(E,b)}}else this.stalled=T}}}else if(this.moved=!0,null!==n){if(this.stallReported){var S=self.performance.now()-n;l.b.warn("playback not stuck anymore @"+a+", after "+Math.round(S)+"ms"),this.stallReported=!1}this.stalled=null,this.nudgeRetry=0}}},e._tryFixBufferStall=function(t,e){var i=this.config,r=this.fragmentTracker,n=this.media;if(null!==n){var a=n.currentTime,s=r.getPartialFragment(a);if(s)if(this._trySkipBufferHole(s)||!this.media)return;t.len>i.maxBufferHole&&e>1e3*i.highBufferWatchdogPeriod&&(l.b.warn("Trying to nudge playhead over buffer-hole"),this.stalled=null,this._tryNudgeBuffer())}},e._reportStall=function(t){var e=this.hls,i=this.media;!this.stallReported&&i&&(this.stallReported=!0,l.b.warn("Playback stalling at @"+i.currentTime+" due to low buffer ("+JSON.stringify(t)+")"),e.trigger(s.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_STALLED_ERROR,fatal:!1,buffer:t.len}))},e._trySkipBufferHole=function(t){var e=this.config,i=this.hls,r=this.media;if(null===r)return 0;for(var n=r.currentTime,a=0,u=mt.getBuffered(r),h=0;h=a&&n1?(r=0,this.bitrateTest=!0):r=i.nextAutoLevel),this.level=i.nextLoadLevel=r,this.loadedmetadata=!1}e>0&&-1===t&&(this.log("Override startPosition with lastCurrentTime @"+e.toFixed(3)),t=e),this.state=Ht,this.nextLoadPosition=this.startPosition=this.lastCurrentTime=t,this.tick()}else this._forceStartLoad=!0,this.state=Kt},h.stopLoad=function(){this._forceStartLoad=!1,t.prototype.stopLoad.call(this)},h.doTick=function(){switch(this.state){case Ht:this.doTickIdle();break;case Zt:var t,e=this.levels,i=this.level,r=null==e||null===(t=e[i])||void 0===t?void 0:t.details;if(r&&(!r.live||this.levelLastLoaded===this.level)){if(this.waitForCdnTuneIn(r))break;this.state=Ht;break}break;case Yt:var n,a=self.performance.now(),s=this.retryDate;(!s||a>=s||null!==(n=this.media)&&void 0!==n&&n.seeking)&&(this.log("retryDate reached, switch back to IDLE state"),this.resetStartWhenNotLoaded(this.level),this.state=Ht)}this.onTickEnd()},h.onTickEnd=function(){t.prototype.onTickEnd.call(this),this.checkBuffer(),this.checkFragmentChanged()},h.doTickIdle=function(){var t,e,i=this.hls,r=this.levelLastLoaded,n=this.levels,a=this.media,o=i.config,l=i.nextLoadLevel;if(null!==r&&(a||!this.startFragRequested&&o.startFragPrefetch)&&(!this.altAudio||!this.audioOnly)&&n&&n[l]){var u=n[l];this.level=i.nextLoadLevel=l;var h=u.details;if(!h||this.state===Zt||h.live&&this.levelLastLoaded!==l)this.state=Zt;else{var d=this.getMainFwdBufferInfo();if(null!==d)if(!(d.len>=this.getMaxBufferLength(u.maxBitrate))){if(this._streamEnded(d,h)){var c={};return this.altAudio&&(c.type="video"),this.hls.trigger(s.a.BUFFER_EOS,c),void(this.state=Qt)}this.backtrackFragment&&this.backtrackFragment.start>d.end&&(this.backtrackFragment=null);var f=this.backtrackFragment?this.backtrackFragment.start:d.end,g=this.getNextFragment(f,h);if(this.couldBacktrack&&!this.fragPrevious&&g&&"initSegment"!==g.sn&&this.fragmentTracker.getState(g)!==ut.OK){var v,m=(null!=(v=this.backtrackFragment)?v:g).sn-h.startSN,y=h.fragments[m-1];y&&g.cc===y.cc&&(g=y,this.fragmentTracker.removeFragment(y))}else this.backtrackFragment&&d.len&&(this.backtrackFragment=null);if(g&&this.fragmentTracker.getState(g)===ut.OK&&this.nextLoadPosition>f){var T=this.audioOnly&&!this.altAudio?p.a.AUDIO:p.a.VIDEO;a&&this.afterBufferFlushed(a,T,w.b.MAIN),g=this.getNextFragment(this.nextLoadPosition,h)}g&&(!g.initSegment||g.initSegment.data||this.bitrateTest||(g=g.initSegment),"identity"!==(null===(t=g.decryptdata)||void 0===t?void 0:t.keyFormat)||null!==(e=g.decryptdata)&&void 0!==e&&e.key?this.loadFragment(g,h,f):this.loadKey(g,h))}}}},h.loadFragment=function(e,i,r){var n,a=this.fragmentTracker.getState(e);this.fragCurrent=e,a===ut.NOT_LOADED?"initSegment"===e.sn?this._loadInitSegment(e):this.bitrateTest?(this.log("Fragment "+e.sn+" of level "+e.level+" is being downloaded to test bitrate and will not be buffered"),this._loadBitrateTestFrag(e)):(this.startFragRequested=!0,t.prototype.loadFragment.call(this,e,i,r)):a===ut.APPENDING?this.reduceMaxBufferLength(e.duration)&&this.fragmentTracker.removeFragment(e):0===(null===(n=this.media)||void 0===n?void 0:n.buffered.length)&&this.fragmentTracker.removeAllFragments()},h.getAppendedFrag=function(t){var e=this.fragmentTracker.getAppendedFrag(t,w.b.MAIN);return e&&"fragment"in e?e.fragment:e},h.getBufferedFrag=function(t){return this.fragmentTracker.getBufferedFrag(t,w.b.MAIN)},h.followingBufferedFrag=function(t){return t?this.getBufferedFrag(t.end+.5):null},h.immediateLevelSwitch=function(){this.abortCurrentFrag(),this.flushMainBuffer(0,Number.POSITIVE_INFINITY)},h.nextLevelSwitch=function(){var t=this.levels,e=this.media;if(null!=e&&e.readyState){var i,r=this.getAppendedFrag(e.currentTime);if(r&&r.start>1&&this.flushMainBuffer(0,r.start-1),!e.paused&&t){var n=t[this.hls.nextLoadLevel],a=this.fragLastKbps;i=a&&this.fragCurrent?this.fragCurrent.duration*n.maxBitrate/(1e3*a)+1:0}else i=0;var s=this.getBufferedFrag(e.currentTime+i);if(s){var o=this.followingBufferedFrag(s);if(o){this.abortCurrentFrag();var l=o.maxStartPTS?o.maxStartPTS:o.start,u=o.duration,h=Math.max(s.end,l+Math.min(Math.max(u-this.config.maxFragLookUpTolerance,.5*u),.75*u));this.flushMainBuffer(h,Number.POSITIVE_INFINITY)}}}},h.abortCurrentFrag=function(){var t=this.fragCurrent;switch(this.fragCurrent=null,this.backtrackFragment=null,null!=t&&t.loader&&t.loader.abort(),this.state){case Vt:case Wt:case Yt:case zt:case Xt:this.state=Ht}this.nextLoadPosition=this.getLoadPosition()},h.flushMainBuffer=function(e,i){t.prototype.flushMainBuffer.call(this,e,i,this.altAudio?"video":null)},h.onMediaAttached=function(e,i){t.prototype.onMediaAttached.call(this,e,i);var r=i.media;this.onvplaying=this.onMediaPlaying.bind(this),this.onvseeked=this.onMediaSeeked.bind(this),r.addEventListener("playing",this.onvplaying),r.addEventListener("seeked",this.onvseeked),this.gapController=new le(this.config,r,this.fragmentTracker,this.hls)},h.onMediaDetaching=function(){var e=this.media;e&&this.onvplaying&&this.onvseeked&&(e.removeEventListener("playing",this.onvplaying),e.removeEventListener("seeked",this.onvseeked),this.onvplaying=this.onvseeked=null,this.videoBuffer=null),this.fragPlaying=null,this.gapController&&(this.gapController.destroy(),this.gapController=null),t.prototype.onMediaDetaching.call(this)},h.onMediaPlaying=function(){this.tick()},h.onMediaSeeked=function(){var t=this.media,e=t?t.currentTime:null;Object(a.a)(e)&&this.log("Media seeked to "+e.toFixed(3)),this.tick()},h.onManifestLoading=function(){this.log("Trigger BUFFER_RESET"),this.hls.trigger(s.a.BUFFER_RESET,void 0),this.fragmentTracker.removeAllFragments(),this.couldBacktrack=!1,this.startPosition=this.lastCurrentTime=0,this.fragPlaying=null,this.backtrackFragment=null},h.onManifestParsed=function(t,e){var i,r,n,a=!1,s=!1;e.levels.forEach((function(t){(i=t.audioCodec)&&(-1!==i.indexOf("mp4a.40.2")&&(a=!0),-1!==i.indexOf("mp4a.40.5")&&(s=!0))})),this.audioCodecSwitch=a&&s&&!("function"==typeof(null==(n=ie())||null===(r=n.prototype)||void 0===r?void 0:r.changeType)),this.audioCodecSwitch&&this.log("Both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC"),this.levels=e.levels,this.startFragRequested=!1},h.onLevelLoading=function(t,e){var i=this.levels;if(i&&this.state===Ht){var r=i[e.level];(!r.details||r.details.live&&this.levelLastLoaded!==e.level||this.waitForCdnTuneIn(r.details))&&(this.state=Zt)}},h.onLevelLoaded=function(t,e){var i,r=this.levels,n=e.level,a=e.details,o=a.totalduration;if(r){this.log("Level "+n+" loaded ["+a.startSN+","+a.endSN+"], cc ["+a.startCC+", "+a.endCC+"] duration:"+o);var l=this.fragCurrent;!l||this.state!==Wt&&this.state!==Yt||l.level!==e.level&&l.loader&&(this.state=Ht,this.backtrackFragment=null,l.loader.abort());var u=r[n],h=0;if(a.live||null!==(i=u.details)&&void 0!==i&&i.live){if(a.fragments[0]||(a.deltaUpdateFailed=!0),a.deltaUpdateFailed)return;h=this.alignPlaylists(a,u.details)}if(u.details=a,this.levelLastLoaded=n,this.hls.trigger(s.a.LEVEL_UPDATED,{details:a,level:n}),this.state===Zt){if(this.waitForCdnTuneIn(a))return;this.state=Ht}this.startFragRequested?a.live&&this.synchronizeToLiveEdge(a):this.setStartPosition(a,h),this.tick()}else this.warn("Levels were reset while loading level "+n)},h._handleFragmentLoadProgress=function(t){var e,i=t.frag,r=t.part,n=t.payload,a=this.levels;if(a){var s=a[i.level],o=s.details;if(o){var l=s.videoCodec,u=o.PTSKnown||!o.live,h=null===(e=i.initSegment)||void 0===e?void 0:e.data,d=this._getAudioCodec(s),c=this.transmuxer=this.transmuxer||new oe(this.hls,w.b.MAIN,this._handleTransmuxComplete.bind(this),this._handleTransmuxerFlush.bind(this)),f=r?r.index:-1,g=-1!==f,v=new yt(i.level,i.sn,i.stats.chunkCount,n.byteLength,f,g),p=this.initPTS[i.cc];c.push(n,h,d,l,i,r,o.totalduration,u,v,p)}else this.warn("Dropping fragment "+i.sn+" of level "+i.level+" after level details were reset")}else this.warn("Levels were reset while fragment load was in progress. Fragment "+i.sn+" of level "+i.level+" will not be buffered")},h.onAudioTrackSwitching=function(t,e){var i=this.altAudio,r=!!e.url,n=e.id;if(!r){if(this.mediaBuffer!==this.media){this.log("Switching on main audio, use media.buffered to schedule main fragment loading"),this.mediaBuffer=this.media;var a=this.fragCurrent;null!=a&&a.loader&&(this.log("Switching to main audio track, cancel main fragment load"),a.loader.abort()),this.resetTransmuxer(),this.resetLoadingState()}else this.audioOnly&&this.resetTransmuxer();var o=this.hls;i&&o.trigger(s.a.BUFFER_FLUSHING,{startOffset:0,endOffset:Number.POSITIVE_INFINITY,type:"audio"}),o.trigger(s.a.AUDIO_TRACK_SWITCHED,{id:n})}},h.onAudioTrackSwitched=function(t,e){var i=e.id,r=!!this.hls.audioTracks[i].url;if(r){var n=this.videoBuffer;n&&this.mediaBuffer!==n&&(this.log("Switching on alternate audio, use video.buffered to schedule main fragment loading"),this.mediaBuffer=n)}this.altAudio=r,this.tick()},h.onBufferCreated=function(t,e){var i,r,n=e.tracks,a=!1;for(var s in n){var o=n[s];if("main"===o.id){if(r=s,i=o,"video"===s){var l=n[s];l&&(this.videoBuffer=l.buffer)}}else a=!0}a&&i?(this.log("Alternate track found, use "+r+".buffered to schedule main fragment loading"),this.mediaBuffer=i.buffer):this.mediaBuffer=this.media},h.onFragBuffered=function(t,e){var i=e.frag,r=e.part;if(!i||i.type===w.b.MAIN){if(this.fragContextChanged(i))return this.warn("Fragment "+i.sn+(r?" p: "+r.index:"")+" of level "+i.level+" finished buffering, but was aborted. state: "+this.state),void(this.state===Xt&&(this.state=Ht));var n=r?r.stats:i.stats;this.fragLastKbps=Math.round(8*n.total/(n.buffering.end-n.loading.first)),"initSegment"!==i.sn&&(this.fragPrevious=i),this.fragBufferedComplete(i,r)}},h.onError=function(t,e){switch(e.details){case o.a.FRAG_LOAD_ERROR:case o.a.FRAG_LOAD_TIMEOUT:case o.a.KEY_LOAD_ERROR:case o.a.KEY_LOAD_TIMEOUT:this.onFragmentOrKeyLoadError(w.b.MAIN,e);break;case o.a.LEVEL_LOAD_ERROR:case o.a.LEVEL_LOAD_TIMEOUT:this.state!==$t&&(e.fatal?(this.warn(""+e.details),this.state=$t):e.levelRetry||this.state!==Zt||(this.state=Ht));break;case o.a.BUFFER_FULL_ERROR:if("main"===e.parent&&(this.state===zt||this.state===Xt)){var i=!0,r=this.getFwdBufferInfo(this.media,w.b.MAIN);r&&r.len>.5&&(i=!this.reduceMaxBufferLength(r.len)),i&&(this.warn("buffer full error also media.currentTime is not buffered, flush main"),this.immediateLevelSwitch()),this.resetLoadingState()}}},h.checkBuffer=function(){var t=this.media,e=this.gapController;if(t&&e&&t.readyState){if(this.loadedmetadata||!mt.getBuffered(t).length){var i=this.state!==Ht?this.fragCurrent:null;e.poll(this.lastCurrentTime,i)}this.lastCurrentTime=t.currentTime}},h.onFragLoadEmergencyAborted=function(){this.state=Ht,this.loadedmetadata||(this.startFragRequested=!1,this.nextLoadPosition=this.startPosition),this.tickImmediate()},h.onBufferFlushed=function(t,e){var i=e.type;if(i!==p.a.AUDIO||this.audioOnly&&!this.altAudio){var r=(i===p.a.VIDEO?this.videoBuffer:this.mediaBuffer)||this.media;this.afterBufferFlushed(r,i,w.b.MAIN)}},h.onLevelsUpdated=function(t,e){this.levels=e.levels},h.swapAudioCodec=function(){this.audioCodecSwap=!this.audioCodecSwap},h.seekToStartPos=function(){var t=this.media;if(t){var e=t.currentTime,i=this.startPosition;if(i>=0&&e0&&(n1&&!1===t.seeking){var i=t.currentTime;if(mt.isBuffered(t,i)?e=this.getAppendedFrag(i):mt.isBuffered(t,i+.1)&&(e=this.getAppendedFrag(i+.1)),e){this.backtrackFragment=null;var r=this.fragPlaying,n=e.level;r&&e.sn===r.sn&&r.level===n&&e.urlId===r.urlId||(this.hls.trigger(s.a.FRAG_CHANGED,{frag:e}),r&&r.level===n||this.hls.trigger(s.a.LEVEL_SWITCHED,{level:n}),this.fragPlaying=e)}}},n=r,(l=[{key:"nextLevel",get:function(){var t=this.nextBufferedFrag;return t?t.level:-1}},{key:"currentFrag",get:function(){var t=this.media;return t?this.fragPlaying||this.getAppendedFrag(t.currentTime):null}},{key:"currentProgramDateTime",get:function(){var t=this.media;if(t){var e=t.currentTime,i=this.currentFrag;if(i&&Object(a.a)(e)&&Object(a.a)(i.programDateTime)){var r=i.programDateTime+1e3*(e-i.start);return new Date(r)}}return null}},{key:"currentLevel",get:function(){var t=this.currentFrag;return t?t.level:-1}},{key:"nextBufferedFrag",get:function(){var t=this.currentFrag;return t?this.followingBufferedFrag(t):null}},{key:"forceStartLoad",get:function(){return this._forceStartLoad}}])&&ue(n.prototype,l),u&&ue(n,u),Object.defineProperty(n,"prototype",{writable:!1}),r}(te),ce=function(){function t(t,e,i){void 0===e&&(e=0),void 0===i&&(i=0),this.halfLife=void 0,this.alpha_=void 0,this.estimate_=void 0,this.totalWeight_=void 0,this.halfLife=t,this.alpha_=t?Math.exp(Math.log(.5)/t):0,this.estimate_=e,this.totalWeight_=i}var e=t.prototype;return e.sample=function(t,e){var i=Math.pow(this.alpha_,t);this.estimate_=e*(1-i)+i*this.estimate_,this.totalWeight_+=t},e.getTotalWeight=function(){return this.totalWeight_},e.getEstimate=function(){if(this.alpha_){var t=1-Math.pow(this.alpha_,this.totalWeight_);if(t)return this.estimate_/t}return this.estimate_},t}(),fe=function(){function t(t,e,i){this.defaultEstimate_=void 0,this.minWeight_=void 0,this.minDelayMs_=void 0,this.slow_=void 0,this.fast_=void 0,this.defaultEstimate_=i,this.minWeight_=.001,this.minDelayMs_=50,this.slow_=new ce(t),this.fast_=new ce(e)}var e=t.prototype;return e.update=function(t,e){var i=this.slow_,r=this.fast_;this.slow_.halfLife!==t&&(this.slow_=new ce(t,i.getEstimate(),i.getTotalWeight())),this.fast_.halfLife!==e&&(this.fast_=new ce(e,r.getEstimate(),r.getTotalWeight()))},e.sample=function(t,e){var i=(t=Math.max(t,this.minDelayMs_))/1e3,r=8*e/i;this.fast_.sample(i,r),this.slow_.sample(i,r)},e.canEstimate=function(){var t=this.fast_;return t&&t.getTotalWeight()>=this.minWeight_},e.getEstimate=function(){return this.canEstimate()?Math.min(this.fast_.getEstimate(),this.slow_.getEstimate()):this.defaultEstimate_},e.destroy=function(){},t}();function ge(t,e){for(var i=0;ip;S--){var A=v[S].maxBitrate;if((L=T?u*A/(6.4*T):u*A/g)=b||(l.b.warn("Fragment "+t.sn+(e?" part "+e.index:"")+" of level "+t.level+" is loading too slowly and will cause an underbuffer; aborting and switching to level "+S+"\n Current BW estimate: "+(Object(a.a)(g)?(g/1024).toFixed(3):"Unknown")+" Kb/s\n Estimated load time for current fragment: "+b.toFixed(3)+" s\n Estimated load time for the next fragment: "+L.toFixed(3)+" s\n Time to underbuffer: "+E.toFixed(3)+" s"),i.nextLoadLevel=S,f&&this.bwEstimator.sample(d,o.loaded),this.clearTimer(),t.loader&&(this.fragCurrent=this.partCurrent=null,t.loader.abort()),i.trigger(s.a.FRAG_LOAD_EMERGENCY_ABORTED,{frag:t,part:e,stats:o}))}}}}}},n.onFragLoaded=function(t,e){var i=e.frag,r=e.part;if(i.type===w.b.MAIN&&Object(a.a)(i.sn)){var n=r?r.stats:i.stats,o=r?r.duration:i.duration;if(this.clearTimer(),this.lastLoadedFragLevel=i.level,this._nextAutoLevel=-1,this.hls.config.abrMaxWithRealBitrate){var l=this.hls.levels[i.level],u=(l.loaded?l.loaded.bytes:0)+n.loaded,h=(l.loaded?l.loaded.duration:0)+o;l.loaded={bytes:u,duration:h},l.realBitrate=Math.round(8*u/h)}if(i.bitrateTest){var d={stats:n,frag:i,part:r,id:i.type};this.onFragBuffered(s.a.FRAG_BUFFERED,d)}}},n.onFragBuffered=function(t,e){var i=e.frag,r=e.part,n=r?r.stats:i.stats;if(!n.aborted&&i.type===w.b.MAIN&&"initSegment"!==i.sn){var a=n.parsing.end-n.loading.start;this.bwEstimator.sample(a,n.loaded),n.bwEstimate=this.bwEstimator.getEstimate(),i.bitrateTest?this.bitrateTestDelay=a/1e3:this.bitrateTestDelay=0}},n.onError=function(t,e){switch(e.details){case o.a.FRAG_LOAD_ERROR:case o.a.FRAG_LOAD_TIMEOUT:this.clearTimer()}},n.clearTimer=function(){self.clearInterval(this.timer),this.timer=void 0},n.getNextABRAutoLevel=function(){var t=this.fragCurrent,e=this.partCurrent,i=this.hls,r=i.maxAutoLevel,n=i.config,a=i.minAutoLevel,s=i.media,o=e?e.duration:t?t.duration:0,u=(s&&s.currentTime,s&&0!==s.playbackRate?Math.abs(s.playbackRate):1),h=this.bwEstimator?this.bwEstimator.getEstimate():n.abrEwmaDefaultEstimate,d=i.mainForwardBufferInfo,c=(d?d.len:0)/u,f=this.findBestLevel(h,a,r,c,n.abrBandWidthFactor,n.abrBandWidthUpFactor);if(f>=0)return f;l.b.trace((c?"rebuffering expected":"buffer is empty")+", finding optimal quality level");var g=o?Math.min(o,n.maxStarvationDelay):n.maxStarvationDelay,v=n.abrBandWidthFactor,p=n.abrBandWidthUpFactor;if(!c){var m=this.bitrateTestDelay;if(m)g=(o?Math.min(o,n.maxLoadingDelay):n.maxLoadingDelay)-m,l.b.trace("bitrate test took "+Math.round(1e3*m)+"ms, set first fragment max fetchDuration to "+Math.round(1e3*g)+" ms"),v=p=1}return f=this.findBestLevel(h,a,r,c+g,v,p),Math.max(f,0)},n.findBestLevel=function(t,e,i,r,n,s){for(var o,u=this.fragCurrent,h=this.partCurrent,d=this.lastLoadedFragLevel,c=this.hls.levels,f=c[d],g=!(null==f||null===(o=f.details)||void 0===o||!o.live),v=null==f?void 0:f.codecSet,p=h?h.duration:u?u.duration:0,m=i;m>=e;m--){var y=c[m];if(y&&(!v||y.codecSet===v)){var T=y.details,b=(h?null==T?void 0:T.partTarget:null==T?void 0:T.averagetargetduration)||p,E=void 0;E=m<=d?n*t:s*t;var S=c[m].maxBitrate,L=S*b/E;if(l.b.trace("level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: "+m+"/"+Math.round(E)+"/"+S+"/"+b+"/"+r+"/"+L),E>S&&(0===L||!Object(a.a)(L)||g&&!this.bitrateTestDelay||L0&&-1===t?(this.log("Override startPosition with lastCurrentTime @"+e.toFixed(3)),t=e,this.state=Ht):(this.loadedmetadata=!1,this.state=qt),this.nextLoadPosition=this.startPosition=this.lastCurrentTime=t,this.tick()},n.doTick=function(){switch(this.state){case Ht:this.doTickIdle();break;case qt:var e,i=this.levels,r=this.trackId,n=null==i||null===(e=i[r])||void 0===e?void 0:e.details;if(n){if(this.waitForCdnTuneIn(n))break;this.state=Jt}break;case Yt:var a,s=performance.now(),o=this.retryDate;(!o||s>=o||null!==(a=this.media)&&void 0!==a&&a.seeking)&&(this.log("RetryDate reached, switch back to IDLE state"),this.resetStartWhenNotLoaded(this.trackId),this.state=Ht);break;case Jt:var l=this.waitingData;if(l){var u=l.frag,h=l.part,d=l.cache,c=l.complete;if(void 0!==this.initPTS[u.cc]){this.waitingData=null,this.waitingVideoCC=-1,this.state=Wt;var f={frag:u,part:h,payload:d.flush(),networkDetails:null};this._handleFragmentLoadProgress(f),c&&t.prototype._handleFragmentLoadComplete.call(this,f)}else if(this.videoTrackCC!==this.waitingVideoCC)this.log("Waiting fragment cc ("+u.cc+") cancelled because video is at cc "+this.videoTrackCC),this.clearWaitingFragment();else{var g=this.getLoadPosition(),v=mt.bufferInfo(this.mediaBuffer,g,this.config.maxBufferHole);Rt(v.end,this.config.maxFragLookUpTolerance,u)<0&&(this.log("Waiting fragment cc ("+u.cc+") @ "+u.start+" cancelled because another fragment at "+v.end+" is needed"),this.clearWaitingFragment())}}else this.state=Ht}this.onTickEnd()},n.clearWaitingFragment=function(){var t=this.waitingData;t&&(this.fragmentTracker.removeFragment(t.frag),this.waitingData=null,this.waitingVideoCC=-1,this.state=Ht)},n.resetLoadingState=function(){this.clearWaitingFragment(),t.prototype.resetLoadingState.call(this)},n.onTickEnd=function(){var t=this.media;if(t&&t.readyState){var e=(this.mediaBuffer?this.mediaBuffer:t).buffered;!this.loadedmetadata&&e.length&&(this.loadedmetadata=!0),this.lastCurrentTime=t.currentTime}},n.doTickIdle=function(){var t,e,i=this.hls,r=this.levels,n=this.media,a=this.trackId,o=i.config;if(r&&r[a]&&(n||!this.startFragRequested&&o.startFragPrefetch)){var l=r[a].details;if(!l||l.live&&this.levelLastLoaded!==a||this.waitForCdnTuneIn(l))this.state=qt;else{var u=this.mediaBuffer?this.mediaBuffer:this.media;this.bufferFlushed&&u&&(this.bufferFlushed=!1,this.afterBufferFlushed(u,p.a.AUDIO,w.b.AUDIO));var h=this.getFwdBufferInfo(u,w.b.AUDIO);if(null!==h){var d=this.getFwdBufferInfo(this.videoBuffer?this.videoBuffer:this.media,w.b.MAIN),c=h.len,f=this.getMaxBufferLength(null==d?void 0:d.len),g=this.audioSwitch;if(!(c>=f)||g){if(!g&&this._streamEnded(h,l))return i.trigger(s.a.BUFFER_EOS,{type:"audio"}),void(this.state=Qt);var v=l.fragments[0].start,m=h.end;if(g&&n){var y=this.getLoadPosition();m=y,l.PTSKnown&&yv||h.nextStart)&&(this.log("Alt audio track ahead of main track, seek to start of alt audio track"),n.currentTime=v+.05)}if(!(d&&m>d.end+l.targetduration)&&(d&&d.len||!h.len)){var T=this.getNextFragment(m,l);T?"identity"!==(null===(t=T.decryptdata)||void 0===t?void 0:t.keyFormat)||null!==(e=T.decryptdata)&&void 0!==e&&e.key?this.loadFragment(T,l,m):this.loadKey(T,l):this.bufferFlushed=!0}}}}}},n.getMaxBufferLength=function(e){var i=t.prototype.getMaxBufferLength.call(this);return e?Math.max(i,e):i},n.onMediaDetaching=function(){this.videoBuffer=null,t.prototype.onMediaDetaching.call(this)},n.onAudioTracksUpdated=function(t,e){var i=e.audioTracks;this.resetTransmuxer(),this.levels=i.map((function(t){return new Q(t)}))},n.onAudioTrackSwitching=function(t,e){var i=!!e.url;this.trackId=e.id;var r=this.fragCurrent;null!=r&&r.loader&&r.loader.abort(),this.fragCurrent=null,this.clearWaitingFragment(),i?this.setInterval(100):this.resetTransmuxer(),i?(this.audioSwitch=!0,this.state=Ht):this.state=Kt,this.tick()},n.onManifestLoading=function(){this.mainDetails=null,this.fragmentTracker.removeAllFragments(),this.startPosition=this.lastCurrentTime=0,this.bufferFlushed=!1},n.onLevelLoaded=function(t,e){this.mainDetails=e.details,null!==this.cachedTrackLoadedData&&(this.hls.trigger(s.a.AUDIO_TRACK_LOADED,this.cachedTrackLoadedData),this.cachedTrackLoadedData=null)},n.onAudioTrackLoaded=function(t,e){var i;if(null!=this.mainDetails){var r=this.levels,n=e.details,a=e.id;if(r){this.log("Track "+a+" loaded ["+n.startSN+","+n.endSN+"],duration:"+n.totalduration);var s=r[a],o=0;if(n.live||null!==(i=s.details)&&void 0!==i&&i.live){var l=this.mainDetails;if(n.fragments[0]||(n.deltaUpdateFailed=!0),n.deltaUpdateFailed||!l)return;!s.details&&n.hasProgramDateTime&&l.hasProgramDateTime?(Lt(n,l),o=n.fragments[0].start):o=this.alignPlaylists(n,s.details)}s.details=n,this.levelLastLoaded=a,this.startFragRequested||!this.mainDetails&&n.live||this.setStartPosition(s.details,o),this.state!==qt||this.waitForCdnTuneIn(n)||(this.state=Ht),this.tick()}else this.warn("Audio tracks were reset while loading level "+a)}else this.cachedTrackLoadedData=e},n._handleFragmentLoadProgress=function(t){var e,i=t.frag,r=t.part,n=t.payload,a=this.config,s=this.trackId,o=this.levels;if(o){var l=o[s],u=l.details,h=a.defaultAudioCodec||l.audioCodec||"mp4a.40.2",d=this.transmuxer;d||(d=this.transmuxer=new oe(this.hls,w.b.AUDIO,this._handleTransmuxComplete.bind(this),this._handleTransmuxerFlush.bind(this)));var c=this.initPTS[i.cc],f=null===(e=i.initSegment)||void 0===e?void 0:e.data;if(void 0!==c){var g=r?r.index:-1,v=-1!==g,p=new yt(i.level,i.sn,i.stats.chunkCount,n.byteLength,g,v);d.push(n,f,h,"",i,r,u.totalduration,!1,p,c)}else{this.log("Unknown video PTS for cc "+i.cc+", waiting for video PTS before demuxing audio frag "+i.sn+" of ["+u.startSN+" ,"+u.endSN+"],track "+s),(this.waitingData=this.waitingData||{frag:i,part:r,cache:new pe,complete:!1}).cache.push(new Uint8Array(n)),this.waitingVideoCC=this.videoTrackCC,this.state=Jt}}else this.warn("Audio tracks were reset while fragment load was in progress. Fragment "+i.sn+" of level "+i.level+" will not be buffered")},n._handleFragmentLoadComplete=function(e){this.waitingData?this.waitingData.complete=!0:t.prototype._handleFragmentLoadComplete.call(this,e)},n.onBufferReset=function(){this.mediaBuffer=this.videoBuffer=null,this.loadedmetadata=!1},n.onBufferCreated=function(t,e){var i=e.tracks.audio;i&&(this.mediaBuffer=i.buffer||null),e.tracks.video&&(this.videoBuffer=e.tracks.video.buffer||null)},n.onFragBuffered=function(t,e){var i=e.frag,r=e.part;i.type===w.b.AUDIO&&(this.fragContextChanged(i)?this.warn("Fragment "+i.sn+(r?" p: "+r.index:"")+" of level "+i.level+" finished buffering, but was aborted. state: "+this.state+", audioSwitch: "+this.audioSwitch):("initSegment"!==i.sn&&(this.fragPrevious=i,this.audioSwitch&&(this.audioSwitch=!1,this.hls.trigger(s.a.AUDIO_TRACK_SWITCHED,{id:this.trackId}))),this.fragBufferedComplete(i,r)))},n.onError=function(e,i){switch(i.details){case o.a.FRAG_LOAD_ERROR:case o.a.FRAG_LOAD_TIMEOUT:case o.a.KEY_LOAD_ERROR:case o.a.KEY_LOAD_TIMEOUT:this.onFragmentOrKeyLoadError(w.b.AUDIO,i);break;case o.a.AUDIO_TRACK_LOAD_ERROR:case o.a.AUDIO_TRACK_LOAD_TIMEOUT:this.state!==$t&&this.state!==Kt&&(this.state=i.fatal?$t:Ht,this.warn(i.details+" while loading frag, switching to "+this.state+" state"));break;case o.a.BUFFER_FULL_ERROR:if("audio"===i.parent&&(this.state===zt||this.state===Xt)){var r=!0,n=this.getFwdBufferInfo(this.mediaBuffer,w.b.AUDIO);n&&n.len>.5&&(r=!this.reduceMaxBufferLength(n.len)),r&&(this.warn("Buffer full error also media.currentTime is not buffered, flush audio buffer"),this.fragCurrent=null,t.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio")),this.resetLoadingState()}}},n.onBufferFlushed=function(t,e){e.type===p.a.AUDIO&&(this.bufferFlushed=!0)},n._handleTransmuxComplete=function(t){var e,i="audio",r=this.hls,n=t.remuxResult,a=t.chunkMeta,o=this.getCurrentContext(a);if(!o)return this.warn("The loading context changed while buffering fragment "+a.sn+" of level "+a.level+". This chunk will not be buffered."),void this.resetStartWhenNotLoaded(a.level);var l=o.frag,u=o.part,h=o.level.details,d=n.audio,c=n.text,f=n.id3,g=n.initSegment;if(!this.fragContextChanged(l)&&h){if(this.state=zt,this.audioSwitch&&d&&this.completeAudioSwitch(),null!=g&&g.tracks&&(this._bufferInitSegment(g.tracks,l,a),r.trigger(s.a.FRAG_PARSING_INIT_SEGMENT,{frag:l,id:i,tracks:g.tracks})),d){var v=d.startPTS,m=d.endPTS,y=d.startDTS,T=d.endDTS;u&&(u.elementaryStreams[p.a.AUDIO]={startPTS:v,endPTS:m,startDTS:y,endDTS:T}),l.setElementaryStreamInfo(p.a.AUDIO,v,m,y,T),this.bufferFragmentData(d,l,u,a)}if(null!=f&&null!==(e=f.samples)&&void 0!==e&&e.length){var b=me({id:i,frag:l,details:h},f);r.trigger(s.a.FRAG_PARSING_METADATA,b)}if(c){var E=me({id:i,frag:l,details:h},c);r.trigger(s.a.FRAG_PARSING_USERDATA,E)}}},n._bufferInitSegment=function(t,e,i){if(this.state===zt){t.video&&delete t.video;var r=t.audio;if(r){r.levelCodec=r.codec,r.id="audio",this.log("Init audio buffer, container:"+r.container+", codecs[parsed]=["+r.codec+"]"),this.hls.trigger(s.a.BUFFER_CODECS,t);var n=r.initSegment;if(null!=n&&n.byteLength){var a={type:"audio",frag:e,part:null,chunkMeta:i,parent:e.type,data:n};this.hls.trigger(s.a.BUFFER_APPENDING,a)}this.tick()}}},n.loadFragment=function(e,i,r){var n=this.fragmentTracker.getState(e);this.fragCurrent=e,(this.audioSwitch||n===ut.NOT_LOADED||n===ut.PARTIAL)&&("initSegment"===e.sn?this._loadInitSegment(e):i.live&&!Object(a.a)(this.initPTS[e.cc])?(this.log("Waiting for video PTS in continuity counter "+e.cc+" of live stream before loading audio fragment "+e.sn+" of level "+this.trackId),this.state=Jt):(this.startFragRequested=!0,t.prototype.loadFragment.call(this,e,i,r)))},n.completeAudioSwitch=function(){var e=this.hls,i=this.media,r=this.trackId;i&&(this.log("Switching audio track : flushing all audio"),t.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio")),this.audioSwitch=!1,e.trigger(s.a.AUDIO_TRACK_SWITCHED,{id:r})},r}(te);function be(t,e){for(var i=0;i=e.length)this.warn("Invalid id passed to audio-track controller");else{this.clearTimer();var i=e[this.trackId];this.log("Now switching to audio-track index "+t);var r=e[t],n=r.id,a=r.groupId,o=void 0===a?"":a,l=r.name,u=r.type,h=r.url;if(this.trackId=t,this.trackName=l,this.selectDefaultTrack=!1,this.hls.trigger(s.a.AUDIO_TRACK_SWITCHING,{id:n,groupId:o,name:l,type:u,url:h}),!r.details||r.details.live){var d=this.switchParams(r.url,null==i?void 0:i.details);this.loadPlaylist(d)}}},u.selectInitialTrack=function(){this.tracksInGroup;var t=this.trackName,e=this.findTrackId(t)||this.findTrackId();-1!==e?this.setAudioTrack(e):(this.warn("No track found for running audio group-ID: "+this.groupId),this.hls.trigger(s.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.AUDIO_TRACK_LOAD_ERROR,fatal:!0}))},u.findTrackId=function(t){for(var e=this.tracksInGroup,i=0;i=n[o].start&&s<=n[o].end){a=n[o];break}var l=i.start+i.duration;a?a.end=l:(a={start:s,end:l},n.push(a)),this.fragmentTracker.fragBuffered(i)}}},l.onBufferFlushing=function(t,e){var i=e.startOffset,r=e.endOffset;if(0===i&&r!==Number.POSITIVE_INFINITY){var n=this.currentTrackId,a=this.levels;if(!a.length||!a[n]||!a[n].details)return;var s=r-a[n].details.targetduration;if(s<=0)return;e.endOffsetSubtitles=Math.max(0,s),this.tracksBuffered.forEach((function(t){for(var e=0;e=s.length||n!==a)&&o){if(this.mediaBuffer=this.mediaBufferTimeRanges,r.live||null!==(i=o.details)&&void 0!==i&&i.live){var l=this.mainDetails;if(r.deltaUpdateFailed||!l)return;var u=l.fragments[0];if(o.details)0===this.alignPlaylists(r,o.details)&&u&&nt(r,u.start);else r.hasProgramDateTime&&l.hasProgramDateTime?Lt(r,l):u&&nt(r,u.start)}if(o.details=r,this.levelLastLoaded=n,this.tick(),r.live&&!this.fragCurrent&&this.media&&this.state===Ht)Dt(null,r.fragments,this.media.currentTime,0)||(this.warn("Subtitle playlist not aligned with playback"),o.details=void 0)}}},l._handleFragmentLoadComplete=function(t){var e=t.frag,i=t.payload,r=e.decryptdata,n=this.hls;if(!this.fragContextChanged(e)&&i&&i.byteLength>0&&r&&r.key&&r.iv&&"AES-128"===r.method){var a=performance.now();this.decrypter.webCryptoDecrypt(new Uint8Array(i),r.key.buffer,r.iv.buffer).then((function(t){var i=performance.now();n.trigger(s.a.FRAG_DECRYPTED,{frag:e,payload:t,stats:{tstart:a,tdecrypt:i}})}))}},l.doTick=function(){if(this.media){if(this.state===Ht){var t=this.currentTrackId,e=this.levels;if(!e.length||!e[t]||!e[t].details)return;var i=e[t].details,r=i.targetduration,n=this.config,a=this.media,s=mt.bufferedInfo(this.tracksBuffered[this.currentTrackId]||[],a.currentTime-r,n.maxBufferHole),o=s.end;if(s.len>this.getMaxBufferLength()+r)return;var l,u=i.fragments,h=u.length,d=i.edge,c=this.fragPrevious;if(o>>=0)>r-1)throw new DOMException("Failed to execute '"+e+"' on 'TimeRanges': The index provided ("+i+") is greater than the maximum bound ("+r+")");return t[i][e]};this.buffered={get length(){return t.length},end:function(i){return e("end",i,t.length)},start:function(i){return e("start",i,t.length)}}};function ke(t,e){for(var i=0;i-1&&(this.subtitleTrack=this.queuedDefaultTrack,this.queuedDefaultTrack=-1),this.useTextTrackPolling=!(this.media.textTracks&&"onchange"in this.media.textTracks),this.useTextTrackPolling?this.pollTrackChange(500):this.media.textTracks.addEventListener("change",this.asyncPollTrackChange))},l.pollTrackChange=function(t){self.clearInterval(this.subtitlePollingInterval),this.subtitlePollingInterval=self.setInterval(this.trackChangeListener,t)},l.onMediaDetaching=function(){this.media&&(self.clearInterval(this.subtitlePollingInterval),this.useTextTrackPolling||this.media.textTracks.removeEventListener("change",this.asyncPollTrackChange),this.trackId>-1&&(this.queuedDefaultTrack=this.trackId),Ie(this.media.textTracks).forEach((function(t){U(t)})),this.subtitleTrack=-1,this.media=null)},l.onManifestLoading=function(){this.tracks=[],this.groupId=null,this.tracksInGroup=[],this.trackId=-1,this.selectDefaultTrack=!0},l.onManifestParsed=function(t,e){this.tracks=e.subtitleTracks},l.onSubtitleTrackLoaded=function(t,e){var i=e.id,r=e.details,n=this.trackId,a=this.tracksInGroup[n];if(a){var s=a.details;a.details=e.details,this.log("subtitle track "+i+" loaded ["+r.startSN+"-"+r.endSN+"]"),i===this.trackId&&(this.retryCount=0,this.playlistLoaded(i,e,s))}else this.warn("Invalid subtitle track id "+i)},l.onLevelLoading=function(t,e){this.switchLevel(e.level)},l.onLevelSwitching=function(t,e){this.switchLevel(e.level)},l.switchLevel=function(t){var e=this.hls.levels[t];if(null!=e&&e.textGroupIds){var i=e.textGroupIds[e.urlId];if(this.groupId!==i){var r=this.tracksInGroup?this.tracksInGroup[this.trackId]:void 0,n=this.tracks.filter((function(t){return!i||t.groupId===i}));this.tracksInGroup=n;var a=this.findTrackId(null==r?void 0:r.name)||this.findTrackId();this.groupId=i;var o={subtitleTracks:n};this.log("Updating subtitle tracks, "+n.length+' track(s) found in "'+i+'" group-id'),this.hls.trigger(s.a.SUBTITLE_TRACKS_UPDATED,o),-1!==a&&this.setSubtitleTrack(a,r)}}},l.findTrackId=function(t){for(var e=this.tracksInGroup,i=0;i=r.length)){this.clearTimer();var n=r[t];if(this.log("Switching to subtitle track "+t),this.trackId=t,n){var a=n.id,o=n.groupId,l=void 0===o?"":o,u=n.name,h=n.type,d=n.url;this.hls.trigger(s.a.SUBTITLE_TRACK_SWITCH,{id:a,groupId:l,name:u,type:h,url:d});var c=this.switchParams(n.url,null==e?void 0:e.details);this.loadPlaylist(c)}else this.hls.trigger(s.a.SUBTITLE_TRACK_SWITCH,{id:t})}}else this.queuedDefaultTrack=t},l.onTextTracksChanged=function(){if(this.useTextTrackPolling||self.clearInterval(this.subtitlePollingInterval),this.media&&this.hls.config.renderTextTracksNatively){for(var t=-1,e=Ie(this.media.textTracks),i=0;i-1&&this.toggleTrackModes(this.trackId)}},{key:"subtitleTracks",get:function(){return this.tracksInGroup}},{key:"subtitleTrack",get:function(){return this.trackId},set:function(t){this.selectDefaultTrack=!1;var e=this.tracksInGroup?this.tracksInGroup[this.trackId]:void 0;this.setSubtitleTrack(t,e)}}])&&ke(n.prototype,a),o&&ke(n,o),Object.defineProperty(n,"prototype",{writable:!1}),r}(at),we=function(){function t(t){this.buffers=void 0,this.queues={video:[],audio:[],audiovideo:[]},this.buffers=t}var e=t.prototype;return e.append=function(t,e){var i=this.queues[e];i.push(t),1===i.length&&this.buffers[e]&&this.executeNext(e)},e.insertAbort=function(t,e){this.queues[e].unshift(t),this.executeNext(e)},e.appendBlocker=function(t){var e,i=new Promise((function(t){e=t})),r={execute:e,onStart:function(){},onComplete:function(){},onError:function(){}};return this.append(r,t),i},e.executeNext=function(t){var e=this.buffers,i=this.queues,r=e[t],n=i[t];if(n.length){var a=n[0];try{a.execute()}catch(e){l.b.warn("[buffer-operation-queue]: Unhandled exception executing the current operation"),a.onError(e),r&&r.updating||(n.shift(),this.executeNext(t))}}},e.shiftAndExecuteNext=function(t){this.queues[t].shift(),this.executeNext(t)},e.current=function(t){return this.queues[t][0]},t}(),xe=ee(),Pe=/([ha]vc.)(?:\.[^.,]+)+/,Fe=function(){function t(t){var e=this;this.details=null,this._objectUrl=null,this.operationQueue=void 0,this.listeners=void 0,this.hls=void 0,this.bufferCodecEventsExpected=0,this._bufferCodecEventsTotal=0,this.media=null,this.mediaSource=null,this.appendError=0,this.tracks={},this.pendingTracks={},this.sourceBuffer=void 0,this._onMediaSourceOpen=function(){var t=e.hls,i=e.media,r=e.mediaSource;l.b.log("[buffer-controller]: Media source opened"),i&&(e.updateMediaElementDuration(),t.trigger(s.a.MEDIA_ATTACHED,{media:i})),r&&r.removeEventListener("sourceopen",e._onMediaSourceOpen),e.checkPendingTracks()},this._onMediaSourceClose=function(){l.b.log("[buffer-controller]: Media source closed")},this._onMediaSourceEnded=function(){l.b.log("[buffer-controller]: Media source ended")},this.hls=t,this._initSourceBuffer(),this.registerListeners()}var e=t.prototype;return e.hasSourceTypes=function(){return this.getSourceBufferTypes().length>0||Object.keys(this.pendingTracks).length>0},e.destroy=function(){this.unregisterListeners(),this.details=null},e.registerListeners=function(){var t=this.hls;t.on(s.a.MEDIA_ATTACHING,this.onMediaAttaching,this),t.on(s.a.MEDIA_DETACHING,this.onMediaDetaching,this),t.on(s.a.MANIFEST_PARSED,this.onManifestParsed,this),t.on(s.a.BUFFER_RESET,this.onBufferReset,this),t.on(s.a.BUFFER_APPENDING,this.onBufferAppending,this),t.on(s.a.BUFFER_CODECS,this.onBufferCodecs,this),t.on(s.a.BUFFER_EOS,this.onBufferEos,this),t.on(s.a.BUFFER_FLUSHING,this.onBufferFlushing,this),t.on(s.a.LEVEL_UPDATED,this.onLevelUpdated,this),t.on(s.a.FRAG_PARSED,this.onFragParsed,this),t.on(s.a.FRAG_CHANGED,this.onFragChanged,this)},e.unregisterListeners=function(){var t=this.hls;t.off(s.a.MEDIA_ATTACHING,this.onMediaAttaching,this),t.off(s.a.MEDIA_DETACHING,this.onMediaDetaching,this),t.off(s.a.MANIFEST_PARSED,this.onManifestParsed,this),t.off(s.a.BUFFER_RESET,this.onBufferReset,this),t.off(s.a.BUFFER_APPENDING,this.onBufferAppending,this),t.off(s.a.BUFFER_CODECS,this.onBufferCodecs,this),t.off(s.a.BUFFER_EOS,this.onBufferEos,this),t.off(s.a.BUFFER_FLUSHING,this.onBufferFlushing,this),t.off(s.a.LEVEL_UPDATED,this.onLevelUpdated,this),t.off(s.a.FRAG_PARSED,this.onFragParsed,this),t.off(s.a.FRAG_CHANGED,this.onFragChanged,this)},e._initSourceBuffer=function(){this.sourceBuffer={},this.operationQueue=new we(this.sourceBuffer),this.listeners={audio:[],video:[],audiovideo:[]}},e.onManifestParsed=function(t,e){var i=2;(e.audio&&!e.video||!e.altAudio)&&(i=1),this.bufferCodecEventsExpected=this._bufferCodecEventsTotal=i,this.details=null,l.b.log(this.bufferCodecEventsExpected+" bufferCodec event(s) expected")},e.onMediaAttaching=function(t,e){var i=this.media=e.media;if(i&&xe){var r=this.mediaSource=new xe;r.addEventListener("sourceopen",this._onMediaSourceOpen),r.addEventListener("sourceended",this._onMediaSourceEnded),r.addEventListener("sourceclose",this._onMediaSourceClose),i.src=self.URL.createObjectURL(r),this._objectUrl=i.src}},e.onMediaDetaching=function(){var t=this.media,e=this.mediaSource,i=this._objectUrl;if(e){if(l.b.log("[buffer-controller]: media source detaching"),"open"===e.readyState)try{e.endOfStream()}catch(t){l.b.warn("[buffer-controller]: onMediaDetaching: "+t.message+" while calling endOfStream")}this.onBufferReset(),e.removeEventListener("sourceopen",this._onMediaSourceOpen),e.removeEventListener("sourceended",this._onMediaSourceEnded),e.removeEventListener("sourceclose",this._onMediaSourceClose),t&&(i&&self.URL.revokeObjectURL(i),t.src===i?(t.removeAttribute("src"),t.load()):l.b.warn("[buffer-controller]: media.src was changed by a third party - skip cleanup")),this.mediaSource=null,this.media=null,this._objectUrl=null,this.bufferCodecEventsExpected=this._bufferCodecEventsTotal,this.pendingTracks={},this.tracks={}}this.hls.trigger(s.a.MEDIA_DETACHED,void 0)},e.onBufferReset=function(){var t=this;this.getSourceBufferTypes().forEach((function(e){var i=t.sourceBuffer[e];try{i&&(t.removeBufferListeners(e),t.mediaSource&&t.mediaSource.removeSourceBuffer(i),t.sourceBuffer[e]=void 0)}catch(t){l.b.warn("[buffer-controller]: Failed to reset the "+e+" buffer",t)}})),this._initSourceBuffer()},e.onBufferCodecs=function(t,e){var i=this,r=this.getSourceBufferTypes().length;Object.keys(e).forEach((function(t){if(r){var n=i.tracks[t];if(n&&"function"==typeof n.buffer.changeType){var a=e[t],s=a.id,o=a.codec,u=a.levelCodec,h=a.container,d=a.metadata,c=(n.levelCodec||n.codec).replace(Pe,"$1"),f=(u||o).replace(Pe,"$1");if(c!==f){var g=h+";codecs="+(u||o);i.appendChangeType(t,g),l.b.log("[buffer-controller]: switching codec "+c+" to "+f),i.tracks[t]={buffer:n.buffer,codec:o,container:h,levelCodec:u,metadata:d,id:s}}}}else i.pendingTracks[t]=e[t]})),r||(this.bufferCodecEventsExpected=Math.max(this.bufferCodecEventsExpected-1,0),this.mediaSource&&"open"===this.mediaSource.readyState&&this.checkPendingTracks())},e.appendChangeType=function(t,e){var i=this,r=this.operationQueue,n={execute:function(){var n=i.sourceBuffer[t];n&&(l.b.log("[buffer-controller]: changing "+t+" sourceBuffer type to "+e),n.changeType(e)),r.shiftAndExecuteNext(t)},onStart:function(){},onComplete:function(){},onError:function(e){l.b.warn("[buffer-controller]: Failed to change "+t+" SourceBuffer type",e)}};r.append(n,t)},e.onBufferAppending=function(t,e){var i=this,r=this.hls,n=this.operationQueue,a=this.tracks,u=e.data,h=e.type,d=e.frag,c=e.part,f=e.chunkMeta,g=f.buffering[h],v=self.performance.now();g.start=v;var p=d.stats.buffering,m=c?c.stats.buffering:null;0===p.start&&(p.start=v),m&&0===m.start&&(m.start=v);var y=a.audio,T="audio"===h&&1===f.id&&"audio/mpeg"===(null==y?void 0:y.container),b={execute:function(){if(g.executeStart=self.performance.now(),T){var t=i.sourceBuffer[h];if(t){var e=d.start-t.timestampOffset;Math.abs(e)>=.1&&(l.b.log("[buffer-controller]: Updating audio SourceBuffer timestampOffset to "+d.start+" (delta: "+e+") sn: "+d.sn+")"),t.timestampOffset=d.start)}}i.appendExecutor(u,h)},onStart:function(){},onComplete:function(){var t=self.performance.now();g.executeEnd=g.end=t,0===p.first&&(p.first=t),m&&0===m.first&&(m.first=t);var e=i.sourceBuffer,r={};for(var n in e)r[n]=mt.getBuffered(e[n]);i.appendError=0,i.hls.trigger(s.a.BUFFER_APPENDED,{type:h,frag:d,part:c,chunkMeta:f,parent:d.type,timeRanges:r})},onError:function(t){l.b.error("[buffer-controller]: Error encountered while trying to append to the "+h+" SourceBuffer",t);var e={type:o.b.MEDIA_ERROR,parent:d.type,details:o.a.BUFFER_APPEND_ERROR,err:t,fatal:!1};t.code===DOMException.QUOTA_EXCEEDED_ERR?e.details=o.a.BUFFER_FULL_ERROR:(i.appendError++,e.details=o.a.BUFFER_APPEND_ERROR,i.appendError>r.config.appendErrorMaxRetry&&(l.b.error("[buffer-controller]: Failed "+r.config.appendErrorMaxRetry+" times to append segment in sourceBuffer"),e.fatal=!0,r.stopLoad())),r.trigger(s.a.ERROR,e)}};n.append(b,h)},e.onBufferFlushing=function(t,e){var i=this,r=this.operationQueue,n=function(t){return{execute:i.removeExecutor.bind(i,t,e.startOffset,e.endOffset),onStart:function(){},onComplete:function(){i.hls.trigger(s.a.BUFFER_FLUSHED,{type:t})},onError:function(e){l.b.warn("[buffer-controller]: Failed to remove from "+t+" SourceBuffer",e)}}};e.type?r.append(n(e.type),e.type):this.getSourceBufferTypes().forEach((function(t){r.append(n(t),t)}))},e.onFragParsed=function(t,e){var i=this,r=e.frag,n=e.part,a=[],o=n?n.elementaryStreams:r.elementaryStreams;o[p.a.AUDIOVIDEO]?a.push("audiovideo"):(o[p.a.AUDIO]&&a.push("audio"),o[p.a.VIDEO]&&a.push("video"));0===a.length&&l.b.warn("Fragments must have at least one ElementaryStreamType set. type: "+r.type+" level: "+r.level+" sn: "+r.sn),this.blockBuffers((function(){var t=self.performance.now();r.stats.buffering.end=t,n&&(n.stats.buffering.end=t);var e=n?n.stats:r.stats;i.hls.trigger(s.a.FRAG_BUFFERED,{frag:r,part:n,stats:e,id:r.type})}),a)},e.onFragChanged=function(t,e){this.flushBackBuffer()},e.onBufferEos=function(t,e){var i=this;this.getSourceBufferTypes().reduce((function(t,r){var n=i.sourceBuffer[r];return e.type&&e.type!==r||n&&!n.ended&&(n.ended=!0,l.b.log("[buffer-controller]: "+r+" sourceBuffer now EOS")),t&&!(n&&!n.ended)}),!0)&&this.blockBuffers((function(){var t=i.mediaSource;t&&"open"===t.readyState&&t.endOfStream()}))},e.onLevelUpdated=function(t,e){var i=e.details;i.fragments.length&&(this.details=i,this.getSourceBufferTypes().length?this.blockBuffers(this.updateMediaElementDuration.bind(this)):this.updateMediaElementDuration())},e.flushBackBuffer=function(){var t=this.hls,e=this.details,i=this.media,r=this.sourceBuffer;if(i&&null!==e){var n=this.getSourceBufferTypes();if(n.length){var o=e.live&&null!==t.config.liveBackBufferLength?t.config.liveBackBufferLength:t.config.backBufferLength;if(Object(a.a)(o)&&!(o<0)){var l=i.currentTime,u=e.levelTargetDuration,h=Math.max(o,u),d=Math.floor(l/u)*u-h;n.forEach((function(i){var n=r[i];if(n){var a=mt.getBuffered(n);a.length>0&&d>a.start(0)&&(t.trigger(s.a.BACK_BUFFER_REACHED,{bufferEnd:d}),e.live&&t.trigger(s.a.LIVE_BACK_BUFFER_REACHED,{bufferEnd:d}),t.trigger(s.a.BUFFER_FLUSHING,{startOffset:0,endOffset:d,type:i}))}}))}}}},e.updateMediaElementDuration=function(){if(this.details&&this.media&&this.mediaSource&&"open"===this.mediaSource.readyState){var t=this.details,e=this.hls,i=this.media,r=this.mediaSource,n=t.fragments[0].start+t.totalduration,s=i.duration,o=Object(a.a)(r.duration)?r.duration:0;t.live&&e.config.liveDurationInfinity?(l.b.log("[buffer-controller]: Media Source duration is set to Infinity"),r.duration=1/0,this.updateSeekableRange(t)):(n>o&&n>s||!Object(a.a)(s))&&(l.b.log("[buffer-controller]: Updating Media Source duration to "+n.toFixed(3)),r.duration=n)}},e.updateSeekableRange=function(t){var e=this.mediaSource,i=t.fragments;if(i.length&&t.live&&null!=e&&e.setLiveSeekableRange){var r=Math.max(0,i[0].start),n=Math.max(r,r+t.totalduration);e.setLiveSeekableRange(r,n)}},e.checkPendingTracks=function(){var t=this.bufferCodecEventsExpected,e=this.operationQueue,i=this.pendingTracks,r=Object.keys(i).length;if(r&&!t||2===r){this.createSourceBuffers(i),this.pendingTracks={};var n=this.getSourceBufferTypes();if(0===n.length)return void this.hls.trigger(s.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_INCOMPATIBLE_CODECS_ERROR,fatal:!0,reason:"could not create source buffer for media codec(s)"});n.forEach((function(t){e.executeNext(t)}))}},e.createSourceBuffers=function(t){var e=this.sourceBuffer,i=this.mediaSource;if(!i)throw Error("createSourceBuffers called when mediaSource was null");var r=0;for(var n in t)if(!e[n]){var a=t[n];if(!a)throw Error("source buffer exists for track "+n+", however track does not");var u=a.levelCodec||a.codec,h=a.container+";codecs="+u;l.b.log("[buffer-controller]: creating sourceBuffer("+h+")");try{var d=e[n]=i.addSourceBuffer(h),c=n;this.addBufferListener(c,"updatestart",this._onSBUpdateStart),this.addBufferListener(c,"updateend",this._onSBUpdateEnd),this.addBufferListener(c,"error",this._onSBUpdateError),this.tracks[n]={buffer:d,codec:u,container:a.container,levelCodec:a.levelCodec,metadata:a.metadata,id:a.id},r++}catch(t){l.b.error("[buffer-controller]: error while trying to add sourceBuffer: "+t.message),this.hls.trigger(s.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_ADD_CODEC_ERROR,fatal:!1,error:t,mimeType:h})}}r&&this.hls.trigger(s.a.BUFFER_CREATED,{tracks:this.tracks})},e._onSBUpdateStart=function(t){this.operationQueue.current(t).onStart()},e._onSBUpdateEnd=function(t){var e=this.operationQueue;e.current(t).onComplete(),e.shiftAndExecuteNext(t)},e._onSBUpdateError=function(t,e){l.b.error("[buffer-controller]: "+t+" SourceBuffer error",e),this.hls.trigger(s.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_APPENDING_ERROR,fatal:!1});var i=this.operationQueue.current(t);i&&i.onError(e)},e.removeExecutor=function(t,e,i){var r=this.media,n=this.mediaSource,s=this.operationQueue,o=this.sourceBuffer[t];if(!r||!n||!o)return l.b.warn("[buffer-controller]: Attempting to remove from the "+t+" SourceBuffer, but it does not exist"),void s.shiftAndExecuteNext(t);var u=Object(a.a)(r.duration)?r.duration:1/0,h=Object(a.a)(n.duration)?n.duration:1/0,d=Math.max(0,e),c=Math.min(i,u,h);c>d?(l.b.log("[buffer-controller]: Removing ["+d+","+c+"] from the "+t+" SourceBuffer"),o.remove(d,c)):s.shiftAndExecuteNext(t)},e.appendExecutor=function(t,e){var i=this.operationQueue,r=this.sourceBuffer[e];if(!r)return l.b.warn("[buffer-controller]: Attempting to append to the "+e+" SourceBuffer, but it does not exist"),void i.shiftAndExecuteNext(e);r.ended=!1,r.appendBuffer(t)},e.blockBuffers=function(t,e){var i=this;if(void 0===e&&(e=this.getSourceBufferTypes()),!e.length)return l.b.log("[buffer-controller]: Blocking operation requested, but no SourceBuffers exist"),void Promise.resolve().then(t);var r=this.operationQueue,n=e.map((function(t){return r.appendBlocker(t)}));Promise.all(n).then((function(){t(),e.forEach((function(t){var e=i.sourceBuffer[t];e&&e.updating||r.shiftAndExecuteNext(t)}))}))},e.getSourceBufferTypes=function(){return Object.keys(this.sourceBuffer)},e.addBufferListener=function(t,e,i){var r=this.sourceBuffer[t];if(r){var n=i.bind(this,t);this.listeners[t].push({event:e,listener:n}),r.addEventListener(e,n)}},e.removeBufferListeners=function(t){var e=this.sourceBuffer[t];e&&this.listeners[t].forEach((function(t){e.removeEventListener(t.event,t.listener)}))},t}(),Me={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,128:174,129:176,130:189,131:191,132:8482,133:162,134:163,135:9834,136:224,137:32,138:232,139:226,140:234,141:238,142:244,143:251,144:193,145:201,146:211,147:218,148:220,149:252,150:8216,151:161,152:42,153:8217,154:9473,155:169,156:8480,157:8226,158:8220,159:8221,160:192,161:194,162:199,163:200,164:202,165:203,166:235,167:206,168:207,169:239,170:212,171:217,172:249,173:219,174:171,175:187,176:195,177:227,178:205,179:204,180:236,181:210,182:242,183:213,184:245,185:123,186:125,187:92,188:94,189:95,190:124,191:8764,192:196,193:228,194:214,195:246,196:223,197:165,198:164,199:9475,200:197,201:229,202:216,203:248,204:9487,205:9491,206:9495,207:9499},Ne=function(t){var e=t;return Me.hasOwnProperty(t)&&(e=Me[t]),String.fromCharCode(e)},Ue={17:1,18:3,21:5,22:7,23:9,16:11,19:12,20:14},Be={17:2,18:4,21:6,22:8,23:10,19:13,20:15},Ge={25:1,26:3,29:5,30:7,31:9,24:11,27:12,28:14},je={25:2,26:4,29:6,30:8,31:10,27:13,28:15},Ke=["white","green","blue","cyan","red","yellow","magenta","black","transparent"];!function(t){t[t.ERROR=0]="ERROR",t[t.TEXT=1]="TEXT",t[t.WARNING=2]="WARNING",t[t.INFO=2]="INFO",t[t.DEBUG=3]="DEBUG",t[t.DATA=3]="DATA"}(Oe||(Oe={}));var He=function(){function t(){this.time=null,this.verboseLevel=Oe.ERROR}return t.prototype.log=function(t,e){this.verboseLevel>=t&&l.b.log(this.time+" ["+t+"] "+e)},t}(),Ve=function(t){for(var e=[],i=0;i100&&(this.logger.log(Oe.DEBUG,"Too large cursor position "+this.pos),this.pos=100)},e.moveCursor=function(t){var e=this.pos+t;if(t>1)for(var i=this.pos+1;i=144&&this.backSpace();var e=Ne(t);this.pos>=100?this.logger.log(Oe.ERROR,"Cannot insert "+t.toString(16)+" ("+e+") at position "+this.pos+". Skipping it!"):(this.chars[this.pos].setChar(e,this.currPenState),this.moveCursor(1))},e.clearFromPos=function(t){var e;for(e=t;e<100;e++)this.chars[e].reset()},e.clear=function(){this.clearFromPos(0),this.pos=0,this.currPenState.reset()},e.clearToEndOfRow=function(){this.clearFromPos(this.pos)},e.getTextString=function(){for(var t=[],e=!0,i=0;i<100;i++){var r=this.chars[i].uchar;" "!==r&&(e=!1),t.push(r)}return e?"":t.join("")},e.setPenStyles=function(t){this.currPenState.setStyles(t),this.chars[this.pos].setPenState(this.currPenState)},t}(),ze=function(){function t(t){this.rows=void 0,this.currRow=void 0,this.nrRollUpRows=void 0,this.lastOutputScreen=void 0,this.logger=void 0,this.rows=[];for(var e=0;e<15;e++)this.rows.push(new qe(t));this.logger=t,this.currRow=14,this.nrRollUpRows=null,this.lastOutputScreen=null,this.reset()}var e=t.prototype;return e.reset=function(){for(var t=0;t<15;t++)this.rows[t].clear();this.currRow=14},e.equals=function(t){for(var e=!0,i=0;i<15;i++)if(!this.rows[i].equals(t.rows[i])){e=!1;break}return e},e.copy=function(t){for(var e=0;e<15;e++)this.rows[e].copy(t.rows[e])},e.isEmpty=function(){for(var t=!0,e=0;e<15;e++)if(!this.rows[e].isEmpty()){t=!1;break}return t},e.backSpace=function(){this.rows[this.currRow].backSpace()},e.clearToEndOfRow=function(){this.rows[this.currRow].clearToEndOfRow()},e.insertChar=function(t){this.rows[this.currRow].insertChar(t)},e.setPen=function(t){this.rows[this.currRow].setPenStyles(t)},e.moveCursor=function(t){this.rows[this.currRow].moveCursor(t)},e.setCursor=function(t){this.logger.log(Oe.INFO,"setCursor: "+t),this.rows[this.currRow].setCursor(t)},e.setPAC=function(t){this.logger.log(Oe.INFO,"pacData = "+JSON.stringify(t));var e=t.row-1;if(this.nrRollUpRows&&e0&&(i=t?"["+e.join(" | ")+"]":e.join("\n")),i},e.getTextAndFormat=function(){return this.rows},t}(),Xe=function(){function t(t,e,i){this.chNr=void 0,this.outputFilter=void 0,this.mode=void 0,this.verbose=void 0,this.displayedMemory=void 0,this.nonDisplayedMemory=void 0,this.lastOutputScreen=void 0,this.currRollUpRow=void 0,this.writeScreen=void 0,this.cueStartTime=void 0,this.logger=void 0,this.chNr=t,this.outputFilter=e,this.mode=null,this.verbose=0,this.displayedMemory=new ze(i),this.nonDisplayedMemory=new ze(i),this.lastOutputScreen=new ze(i),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null,this.logger=i}var e=t.prototype;return e.reset=function(){this.mode=null,this.displayedMemory.reset(),this.nonDisplayedMemory.reset(),this.lastOutputScreen.reset(),this.outputFilter.reset(),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null},e.getHandler=function(){return this.outputFilter},e.setHandler=function(t){this.outputFilter=t},e.setPAC=function(t){this.writeScreen.setPAC(t)},e.setBkgData=function(t){this.writeScreen.setBkgData(t)},e.setMode=function(t){t!==this.mode&&(this.mode=t,this.logger.log(Oe.INFO,"MODE="+t),"MODE_POP-ON"===this.mode?this.writeScreen=this.nonDisplayedMemory:(this.writeScreen=this.displayedMemory,this.writeScreen.reset()),"MODE_ROLL-UP"!==this.mode&&(this.displayedMemory.nrRollUpRows=null,this.nonDisplayedMemory.nrRollUpRows=null),this.mode=t)},e.insertChars=function(t){for(var e=0;e=46,e.italics)e.foreground="white";else{var i=Math.floor(t/2)-16;e.foreground=["white","green","blue","cyan","red","yellow","magenta"][i]}this.logger.log(Oe.INFO,"MIDROW: "+JSON.stringify(e)),this.writeScreen.setPen(e)},e.outputDataUpdate=function(t){void 0===t&&(t=!1);var e=this.logger.time;null!==e&&this.outputFilter&&(null!==this.cueStartTime||this.displayedMemory.isEmpty()?this.displayedMemory.equals(this.lastOutputScreen)||(this.outputFilter.newCue(this.cueStartTime,e,this.lastOutputScreen),t&&this.outputFilter.dispatchCue&&this.outputFilter.dispatchCue(),this.cueStartTime=this.displayedMemory.isEmpty()?null:e):this.cueStartTime=e,this.lastOutputScreen.copy(this.displayedMemory))},e.cueSplitAtTime=function(t){this.outputFilter&&(this.displayedMemory.isEmpty()||(this.outputFilter.newCue&&this.outputFilter.newCue(this.cueStartTime,t,this.displayedMemory),this.cueStartTime=t))},t}();function Qe(t,e,i){i.a=t,i.b=e}function $e(t,e,i){return i.a===t&&i.b===e}var Je=function(){function t(t,e,i){this.channels=void 0,this.currentChannel=0,this.cmdHistory=void 0,this.logger=void 0;var r=new He;this.channels=[null,new Xe(t,e,r),new Xe(t+1,i,r)],this.cmdHistory={a:null,b:null},this.logger=r}var e=t.prototype;return e.getHandler=function(t){return this.channels[t].getHandler()},e.setHandler=function(t,e){this.channels[t].setHandler(e)},e.addData=function(t,e){var i,r,n,a=!1;this.logger.time=t;for(var s=0;s ("+Ve([r,n])+")"),(i=this.parseCmd(r,n))||(i=this.parseMidrow(r,n)),i||(i=this.parsePAC(r,n)),i||(i=this.parseBackgroundAttributes(r,n)),!i&&(a=this.parseChars(r,n))){var o=this.currentChannel;if(o&&o>0)this.channels[o].insertChars(a);else this.logger.log(Oe.WARNING,"No channel found yet. TEXT-MODE?")}i||a||this.logger.log(Oe.WARNING,"Couldn't parse cleaned data "+Ve([r,n])+" orig: "+Ve([e[s],e[s+1]]))}},e.parseCmd=function(t,e){var i=this.cmdHistory;if(!((20===t||28===t||21===t||29===t)&&e>=32&&e<=47)&&!((23===t||31===t)&&e>=33&&e<=35))return!1;if($e(t,e,i))return Qe(null,null,i),this.logger.log(Oe.DEBUG,"Repeated command ("+Ve([t,e])+") is dropped"),!0;var r=20===t||21===t||23===t?1:2,n=this.channels[r];return 20===t||21===t||28===t||29===t?32===e?n.ccRCL():33===e?n.ccBS():34===e?n.ccAOF():35===e?n.ccAON():36===e?n.ccDER():37===e?n.ccRU(2):38===e?n.ccRU(3):39===e?n.ccRU(4):40===e?n.ccFON():41===e?n.ccRDC():42===e?n.ccTR():43===e?n.ccRTD():44===e?n.ccEDM():45===e?n.ccCR():46===e?n.ccENM():47===e&&n.ccEOC():n.ccTO(e-32),Qe(t,e,i),this.currentChannel=r,!0},e.parseMidrow=function(t,e){var i=0;if((17===t||25===t)&&e>=32&&e<=47){if((i=17===t?1:2)!==this.currentChannel)return this.logger.log(Oe.ERROR,"Mismatch channel in midrow parsing"),!1;var r=this.channels[i];return!!r&&(r.ccMIDROW(e),this.logger.log(Oe.DEBUG,"MIDROW ("+Ve([t,e])+")"),!0)}return!1},e.parsePAC=function(t,e){var i,r=this.cmdHistory;if(!((t>=17&&t<=23||t>=25&&t<=31)&&e>=64&&e<=127)&&!((16===t||24===t)&&e>=64&&e<=95))return!1;if($e(t,e,r))return Qe(null,null,r),!0;var n=t<=23?1:2;i=e>=64&&e<=95?1===n?Ue[t]:Ge[t]:1===n?Be[t]:je[t];var a=this.channels[n];return!!a&&(a.setPAC(this.interpretPAC(i,e)),Qe(t,e,r),this.currentChannel=n,!0)},e.interpretPAC=function(t,e){var i,r={color:null,italics:!1,indent:null,underline:!1,row:t};return i=e>95?e-96:e-64,r.underline=1==(1&i),i<=13?r.color=["white","green","blue","cyan","red","yellow","magenta","white"][Math.floor(i/2)]:i<=15?(r.italics=!0,r.color="white"):r.indent=4*Math.floor((i-16)/2),r},e.parseChars=function(t,e){var i,r,n=null,a=null;(t>=25?(i=2,a=t-8):(i=1,a=t),a>=17&&a<=19)?(r=17===a?e+80:18===a?e+112:e+144,this.logger.log(Oe.INFO,"Special char '"+Ne(r)+"' in channel "+i),n=[r]):t>=32&&t<=127&&(n=0===e?[t]:[t,e]);if(n){var s=Ve(n);this.logger.log(Oe.DEBUG,"Char codes = "+s.join(",")),Qe(t,e,this.cmdHistory)}return n},e.parseBackgroundAttributes=function(t,e){var i;if(!((16===t||24===t)&&e>=32&&e<=47)&&!((23===t||31===t)&&e>=45&&e<=47))return!1;var r={};16===t||24===t?(i=Math.floor((e-32)/2),r.background=Ke[i],e%2==1&&(r.background=r.background+"_semi")):45===e?r.background="transparent":(r.foreground="black",47===e&&(r.underline=!0));var n=t<=23?1:2;return this.channels[n].setBkgData(r),Qe(t,e,this.cmdHistory),!0},e.reset=function(){for(var t=0;tt)&&(this.startTime=t),this.endTime=e,this.screen=i,this.timelineController.createCaptionsTrack(this.trackName)},e.reset=function(){this.cueRanges=[],this.startTime=null},t}(),ti=function(){if("undefined"!=typeof self&&self.VTTCue)return self.VTTCue;var t=["","lr","rl"],e=["start","middle","end","left","right"];function i(t,e){if("string"!=typeof e)return!1;if(!Array.isArray(t))return!1;var i=e.toLowerCase();return!!~t.indexOf(i)&&i}function r(t){return i(e,t)}function n(t){for(var e=arguments.length,i=new Array(e>1?e-1:0),r=1;r100)throw new Error("Position must be between 0 and 100.");T=t,this.hasBeenReset=!0}})),Object.defineProperty(o,"positionAlign",n({},l,{get:function(){return b},set:function(t){var e=r(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");b=e,this.hasBeenReset=!0}})),Object.defineProperty(o,"size",n({},l,{get:function(){return E},set:function(t){if(t<0||t>100)throw new Error("Size must be between 0 and 100.");E=t,this.hasBeenReset=!0}})),Object.defineProperty(o,"align",n({},l,{get:function(){return S},set:function(t){var e=r(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");S=e,this.hasBeenReset=!0}})),o.displayState=void 0}return a.prototype.getCueAsHTML=function(){return self.WebVTT.convertCueToDOMTree(self,this.text)},a}(),ei=function(){function t(){}return t.prototype.decode=function(t,e){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))},t}();function ii(t){function e(t,e,i,r){return 3600*(0|t)+60*(0|e)+(0|i)+parseFloat(r||0)}var i=t.match(/^(?:(\d+):)?(\d{2}):(\d{2})(\.\d+)?/);return i?parseFloat(i[2])>59?e(i[2],i[3],0,i[4]):e(i[1],i[2],i[3],i[4]):null}var ri=function(){function t(){this.values=Object.create(null)}var e=t.prototype;return e.set=function(t,e){this.get(t)||""===e||(this.values[t]=e)},e.get=function(t,e,i){return i?this.has(t)?this.values[t]:e[i]:this.has(t)?this.values[t]:e},e.has=function(t){return t in this.values},e.alt=function(t,e,i){for(var r=0;r=0&&i<=100)return this.set(t,i),!0}return!1},t}();function ni(t,e,i,r){var n=r?t.split(r):[t];for(var a in n)if("string"==typeof n[a]){var s=n[a].split(i);if(2===s.length)e(s[0],s[1])}}var ai=new ti(0,0,""),si="middle"===ai.align?"middle":"center";function oi(t,e,i){var r=t;function n(){var e=ii(t);if(null===e)throw new Error("Malformed timestamp: "+r);return t=t.replace(/^[^\sa-zA-Z-]+/,""),e}function a(){t=t.replace(/^\s+/,"")}if(a(),e.startTime=n(),a(),"--\x3e"!==t.slice(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+r);t=t.slice(3),a(),e.endTime=n(),a(),function(t,e){var r=new ri;ni(t,(function(t,e){var n;switch(t){case"region":for(var a=i.length-1;a>=0;a--)if(i[a].id===e){r.set(t,i[a].region);break}break;case"vertical":r.alt(t,e,["rl","lr"]);break;case"line":n=e.split(","),r.integer(t,n[0]),r.percent(t,n[0])&&r.set("snapToLines",!1),r.alt(t,n[0],["auto"]),2===n.length&&r.alt("lineAlign",n[1],["start",si,"end"]);break;case"position":n=e.split(","),r.percent(t,n[0]),2===n.length&&r.alt("positionAlign",n[1],["start",si,"end","line-left","line-right","auto"]);break;case"size":r.percent(t,e);break;case"align":r.alt(t,e,["start",si,"end","left","right"])}}),/:/,/\s/),e.region=r.get("region",null),e.vertical=r.get("vertical","");var n=r.get("line","auto");"auto"===n&&-1===ai.line&&(n=-1),e.line=n,e.lineAlign=r.get("lineAlign","start"),e.snapToLines=r.get("snapToLines",!0),e.size=r.get("size",100),e.align=r.get("align",si);var a=r.get("position","auto");"auto"===a&&50===ai.position&&(a="start"===e.align||"left"===e.align?0:"end"===e.align||"right"===e.align?100:50),e.position=a}(t,e)}function li(t){return t.replace(//gi,"\n")}var ui=function(){function t(){this.state="INITIAL",this.buffer="",this.decoder=new ei,this.regionList=[],this.cue=null,this.oncue=void 0,this.onparsingerror=void 0,this.onflush=void 0}var e=t.prototype;return e.parse=function(t){var e=this;function i(){var t=e.buffer,i=0;for(t=li(t);i>>0).toString()};function vi(t,e,i){return gi(t.toString())+gi(e.toString())+gi(i)}function pi(t,e,i,r,n,s,o,l){var u,h=new ui,d=Object(G.f)(new Uint8Array(t)).trim().replace(ci,"\n").split("\n"),c=[],f=Object(hi.a)(e,i),g="00:00.000",v=0,p=0,m=!0;h.oncue=function(t){var e=r[n],i=r.ccOffset,a=(v-f)/9e4;null!=e&&e.new&&(void 0!==p?i=r.ccOffset=e.start:function(t,e,i){var r=t[e],n=t[r.prevCC];if(!n||!n.new&&r.new)return t.ccOffset=t.presentationOffset=r.start,void(r.new=!1);for(;null!==(a=n)&&void 0!==a&&a.new;){var a;t.ccOffset+=r.start-n.start,r.new=!1,n=t[(r=n).prevCC]}t.presentationOffset=i}(r,n,a)),a&&(i=a-r.presentationOffset);var o=t.endTime-t.startTime,l=Object(di.d)(9e4*(t.startTime+i-p),9e4*s)/9e4;t.startTime=Math.max(l,0),t.endTime=Math.max(l+o,0);var u=t.text.trim();t.text=decodeURIComponent(encodeURIComponent(u)),t.id||(t.id=vi(t.startTime,t.endTime,u)),t.endTime>0&&c.push(t)},h.onparsingerror=function(t){u=t},h.onflush=function(){u?l(u):o(c)},d.forEach((function(t){if(m){if(fi(t,"X-TIMESTAMP-MAP=")){m=!1,t.slice(16).split(",").forEach((function(t){fi(t,"LOCAL:")?g=t.slice(6):fi(t,"MPEGTS:")&&(v=parseInt(t.slice(7)))}));try{p=function(t){var e=parseInt(t.slice(-3)),i=parseInt(t.slice(-6,-4)),r=parseInt(t.slice(-9,-7)),n=t.length>9?parseInt(t.substring(0,t.indexOf(":"))):0;if(!(Object(a.a)(e)&&Object(a.a)(i)&&Object(a.a)(r)&&Object(a.a)(n)))throw Error("Malformed X-TIMESTAMP-MAP: Local:"+t);return e+=1e3*i,e+=6e4*r,e+=36e5*n}(g)/1e3}catch(t){u=t}return}""===t&&(m=!1)}h.parse(t+"\n")})),h.flush()}function mi(){return(mi=Object.assign?Object.assign.bind():function(t){for(var e=1;e=0&&(c[0]=Math.min(c[0],e),c[1]=Math.max(c[1],i),h=!0,f/(i-e)>.5))return}if(h||n.push([e,i]),this.config.renderTextTracksNatively){var g=this.captionsTracks[t];this.Cues.newCue(g,e,i,r)}else{var v=this.Cues.newCue(null,e,i,r);this.hls.trigger(s.a.CUES_PARSED,{type:"captions",cues:v,track:t})}},e.onInitPtsFound=function(t,e){var i=this,r=e.frag,n=e.id,a=e.initPTS,o=e.timescale,l=this.unparsedVttFrags;"main"===n&&(this.initPTS[r.cc]=a,this.timescale[r.cc]=o),l.length&&(this.unparsedVttFrags=[],l.forEach((function(t){i.onFragLoaded(s.a.FRAG_LOADED,t)})))},e.getExistingTrack=function(t){var e=this.media;if(e)for(var i=0;i0&&this.mediaWidth>0){var t=this.hls.levels;if(t.length){var e=this.hls;e.autoLevelCapping=this.getMaxLevel(t.length-1),e.autoLevelCapping>this.autoLevelCapping&&this.streamController&&this.streamController.nextLevelSwitch(),this.autoLevelCapping=e.autoLevelCapping}}},n.getMaxLevel=function(e){var i=this,r=this.hls.levels;if(!r.length)return-1;var n=r.filter((function(r,n){return t.isLevelAllowed(n,i.restrictedLevels)&&n<=e}));return this.clientRect=null,t.getMaxLevelByMediaSize(n,this.mediaWidth,this.mediaHeight)},n.startCapping=function(){this.timer||(this.autoLevelCapping=Number.POSITIVE_INFINITY,this.hls.firstLevel=this.getMaxLevel(this.firstLevel),self.clearInterval(this.timer),this.timer=self.setInterval(this.detectPlayerSize.bind(this),1e3),this.detectPlayerSize())},n.stopCapping=function(){this.restrictedLevels=[],this.firstLevel=-1,this.autoLevelCapping=Number.POSITIVE_INFINITY,this.timer&&(self.clearInterval(this.timer),this.timer=void 0)},n.getDimensions=function(){if(this.clientRect)return this.clientRect;var t=this.media,e={width:0,height:0};if(t){var i=t.getBoundingClientRect();e.width=i.width,e.height=i.height,e.width||e.height||(e.width=i.right-i.left||t.width||0,e.height=i.bottom-i.top||t.height||0)}return this.clientRect=e,e},t.isLevelAllowed=function(t,e){return void 0===e&&(e=[]),-1===e.indexOf(t)},t.getMaxLevelByMediaSize=function(t,e,i){if(!t||!t.length)return-1;for(var r,n,a=t.length-1,s=0;s=e||o.height>=i)&&(r=o,!(n=t[s+1])||r.width!==n.width||r.height!==n.height)){a=s;break}}return a},e=t,(i=[{key:"mediaWidth",get:function(){return this.getDimensions().width*this.contentScaleFactor}},{key:"mediaHeight",get:function(){return this.getDimensions().height*this.contentScaleFactor}},{key:"contentScaleFactor",get:function(){var t=1;if(!this.hls.config.ignoreDevicePixelRatio)try{t=self.devicePixelRatio}catch(t){}return t}}])&&Ii(e.prototype,i),r&&Ii(e,r),Object.defineProperty(e,"prototype",{writable:!1}),t}(),wi=function(){function t(t){this.hls=void 0,this.isVideoPlaybackQualityAvailable=!1,this.timer=void 0,this.media=null,this.lastTime=void 0,this.lastDroppedFrames=0,this.lastDecodedFrames=0,this.streamController=void 0,this.hls=t,this.registerListeners()}var e=t.prototype;return e.setStreamController=function(t){this.streamController=t},e.registerListeners=function(){this.hls.on(s.a.MEDIA_ATTACHING,this.onMediaAttaching,this)},e.unregisterListeners=function(){this.hls.off(s.a.MEDIA_ATTACHING,this.onMediaAttaching)},e.destroy=function(){this.timer&&clearInterval(this.timer),this.unregisterListeners(),this.isVideoPlaybackQualityAvailable=!1,this.media=null},e.onMediaAttaching=function(t,e){var i=this.hls.config;if(i.capLevelOnFPSDrop){var r=e.media instanceof self.HTMLVideoElement?e.media:null;this.media=r,r&&"function"==typeof r.getVideoPlaybackQuality&&(this.isVideoPlaybackQualityAvailable=!0),self.clearInterval(this.timer),this.timer=self.setInterval(this.checkFPSInterval.bind(this),i.fpsDroppedMonitoringPeriod)}},e.checkFPS=function(t,e,i){var r=performance.now();if(e){if(this.lastTime){var n=r-this.lastTime,a=i-this.lastDroppedFrames,o=e-this.lastDecodedFrames,u=1e3*a/n,h=this.hls;if(h.trigger(s.a.FPS_DROP,{currentDropped:a,currentDecoded:o,totalDroppedFrames:i}),u>0&&a>h.config.fpsDroppedMonitoringThreshold*o){var d=h.currentLevel;l.b.warn("drop FPS ratio greater than max allowed value for currentLevel: "+d),d>0&&(-1===h.autoLevelCapping||h.autoLevelCapping>=d)&&(d-=1,h.trigger(s.a.FPS_DROP_LEVEL_CAPPING,{level:d,droppedLevel:h.currentLevel}),h.autoLevelCapping=d,this.streamController.nextLevelSwitch())}}this.lastTime=r,this.lastDroppedFrames=i,this.lastDecodedFrames=e}},e.checkFPSInterval=function(){var t=this.media;if(t)if(this.isVideoPlaybackQualityAvailable){var e=t.getVideoPlaybackQuality();this.checkFPS(t,e.totalVideoFrames,e.droppedVideoFrames)}else this.checkFPS(t,t.webkitDecodedFrameCount,t.webkitDroppedFrameCount)},t}();!function(t){t.WIDEVINE="com.widevine.alpha",t.PLAYREADY="com.microsoft.playready"}(Oi||(Oi={}));var xi="undefined"!=typeof self&&self.navigator&&self.navigator.requestMediaKeySystemAccess?self.navigator.requestMediaKeySystemAccess.bind(self.navigator):null;function Pi(t,e){for(var i=0;i3)return void this.hls.trigger(s.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0});var u=3-this._requestLicenseFailureCount+1;l.b.warn("Retrying license request, "+u+" attempts left"),this._requestLicense(i,r)}}},n._generateLicenseRequestChallenge=function(t,e){switch(t.mediaKeySystemDomain){case Oi.WIDEVINE:return e}throw new Error("unsupported key-system: "+t.mediaKeySystemDomain)},n._requestLicense=function(t,e){l.b.log("Requesting content license for key-system");var i=this._mediaKeysList[0];if(!i)return l.b.error("Fatal error: Media is encrypted but no key-system access has been obtained yet"),void this.hls.trigger(s.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_NO_ACCESS,fatal:!0});try{var r=this.getLicenseServerUrl(i.mediaKeySystemDomain),n=this._createLicenseXhr(r,t,e);l.b.log("Sending license request to URL: "+r);var a=this._generateLicenseRequestChallenge(i,t);n.send(a)}catch(t){l.b.error("Failure requesting DRM license: "+t),this.hls.trigger(s.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0})}},n.onMediaAttached=function(t,e){if(this._emeEnabled){var i=e.media;this._media=i,i.addEventListener("encrypted",this._onMediaEncrypted)}},n.onMediaDetached=function(){var t=this._media,e=this._mediaKeysList;t&&(t.removeEventListener("encrypted",this._onMediaEncrypted),this._media=null,this._mediaKeysList=[],Promise.all(e.map((function(t){if(t.mediaKeysSession)return t.mediaKeysSession.close().catch((function(){}))}))).then((function(){return t.setMediaKeys(null)})).catch((function(){})))},n.onManifestParsed=function(t,e){if(this._emeEnabled){var i=e.levels.map((function(t){return t.audioCodec})).filter((function(t){return!!t})),r=e.levels.map((function(t){return t.videoCodec})).filter((function(t){return!!t}));this._attemptKeySystemAccess(Oi.WIDEVINE,i,r)}},e=t,(i=[{key:"requestMediaKeySystemAccess",get:function(){if(!this._requestMediaKeySystemAccess)throw new Error("No requestMediaKeySystemAccess function configured");return this._requestMediaKeySystemAccess}}])&&Pi(e.prototype,i),r&&Pi(e,r),Object.defineProperty(e,"prototype",{writable:!1}),t}();function Bi(t,e){for(var i=0;i=t.length?{done:!0}:{done:!1,value:t[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ki(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=new Array(e);i-1?n+1:r.levels.length;e=r.levels.slice(0,a)}for(var s,o=ji(e);!(s=o()).done;){var l=s.value;l.bitrate>i&&(i=l.bitrate)}return i>0?i:NaN},e.getBufferLength=function(t){var e=this.hls.media,i=t===Fi.AUDIO?this.audioBuffer:this.videoBuffer;return i&&e?1e3*mt.bufferInfo(i,e.currentTime,this.config.maxBufferHole).len:NaN},e.createPlaylistLoader=function(){var t=this.config.pLoader,e=this.applyPlaylistData,i=t||this.config.loader;return function(){function t(t){this.loader=void 0,this.loader=new i(t)}var r=t.prototype;return r.destroy=function(){this.loader.destroy()},r.abort=function(){this.loader.abort()},r.load=function(t,i,r){e(t),this.loader.load(t,i,r)},Gi(t,[{key:"stats",get:function(){return this.loader.stats}},{key:"context",get:function(){return this.loader.context}}]),t}()},e.createFragmentLoader=function(){var t=this.config.fLoader,e=this.applyFragmentData,i=t||this.config.loader;return function(){function t(t){this.loader=void 0,this.loader=new i(t)}var r=t.prototype;return r.destroy=function(){this.loader.destroy()},r.abort=function(){this.loader.abort()},r.load=function(t,i,r){e(t),this.loader.load(t,i,r)},Gi(t,[{key:"stats",get:function(){return this.loader.stats}},{key:"context",get:function(){return this.loader.context}}]),t}()},t.uuid=function(){var t=URL.createObjectURL(new Blob),e=t.toString();return URL.revokeObjectURL(t),e.slice(e.lastIndexOf("/")+1)},t.serialize=function(t){for(var e,i=[],r=function(t){return!Number.isNaN(t)&&null!=t&&""!==t&&!1!==t},n=function(t){return Math.round(t)},a=function(t){return 100*n(t/100)},s={br:n,d:n,bl:a,dl:a,mtp:a,nor:function(t){return encodeURIComponent(t)},rtp:a,tb:n},o=ji(Object.keys(t||{}).sort());!(e=o()).done;){var l=e.value,u=t[l];if(r(u)&&!("v"===l&&1===u||"pr"==l&&1===u)){var h=s[l];h&&(u=h(u));var d=typeof u,c=void 0;c="ot"===l||"sf"===l||"st"===l?l+"="+u:"boolean"===d?l:"number"===d?l+"="+u:l+"="+JSON.stringify(u),i.push(c)}}return i.join(",")},t.toHeaders=function(e){for(var i={},r=["Object","Request","Session","Status"],n=[{},{},{},{}],a={br:0,d:0,ot:0,tb:0,bl:1,dl:1,mtp:1,nor:1,nrr:1,su:1,cid:2,pr:2,sf:2,sid:2,st:2,v:2,bs:3,rtp:3},s=0,o=Object.keys(e);s=2)if(self.clearTimeout(this.requestTimeout),0===i.loading.first&&(i.loading.first=Math.max(self.performance.now(),i.loading.start)),4===r){e.onreadystatechange=null,e.onprogress=null;var a=e.status;if(a>=200&&a<300){var s,o;if(i.loading.end=Math.max(self.performance.now(),i.loading.first),o="arraybuffer"===t.responseType?(s=e.response).byteLength:(s=e.responseText).length,i.loaded=i.total=o,!this.callbacks)return;var u=this.callbacks.onProgress;if(u&&u(i,t,s,e),!this.callbacks)return;var h={url:e.responseURL,data:s};this.callbacks.onSuccess(h,i,t,e)}else i.retry>=n.maxRetry||a>=400&&a<499?(l.b.error(a+" while loading "+t.url),this.callbacks.onError({code:a,text:e.statusText},t,e)):(l.b.warn(a+" while loading "+t.url+", retrying in "+this.retryDelay+"..."),this.abortInternal(),this.loader=null,self.clearTimeout(this.retryTimeout),this.retryTimeout=self.setTimeout(this.loadInternal.bind(this),this.retryDelay),this.retryDelay=Math.min(2*this.retryDelay,n.maxRetryDelay),i.retry++)}else self.clearTimeout(this.requestTimeout),this.requestTimeout=self.setTimeout(this.loadtimeout.bind(this),n.timeout)}},e.loadtimeout=function(){l.b.warn("timeout while loading "+this.context.url);var t=this.callbacks;t&&(this.abortInternal(),t.onTimeout(this.stats,this.context,this.loader))},e.loadprogress=function(t){var e=this.stats;e.loaded=t.loaded,t.lengthComputable&&(e.total=t.total)},e.getCacheAge=function(){var t=null;if(this.loader&&Yi.test(this.loader.getAllResponseHeaders())){var e=this.loader.getResponseHeader("age");t=e?parseFloat(e):null}return t},t}();function zi(t){var e="function"==typeof Map?new Map:void 0;return(zi=function(t){if(null===t||(i=t,-1===Function.toString.call(i).indexOf("[native code]")))return t;var i;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,r)}function r(){return Xi(t,arguments,Ji(this).constructor)}return r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),$i(r,t)})(t)}function Xi(t,e,i){return(Xi=Qi()?Reflect.construct.bind():function(t,e,i){var r=[null];r.push.apply(r,e);var n=new(Function.bind.apply(t,r));return i&&$i(n,i.prototype),n}).apply(null,arguments)}function Qi(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function $i(t,e){return($i=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}function Ji(t){return(Ji=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function Zi(){return(Zi=Object.assign?Object.assign.bind():function(t){for(var e=1;e=r&&n(e,i,a.flush(),t)):n(e,i,l,t),o()})).catch((function(){return Promise.reject()}))}()},t}();function er(t,e){return new self.Request(t.url,e)}var ir=function(t){var e,i;function r(e,i,r){var n;return(n=t.call(this,e)||this).code=void 0,n.details=void 0,n.code=i,n.details=r,n}return i=t,(e=r).prototype=Object.create(i.prototype),e.prototype.constructor=e,$i(e,i),r}(zi(Error)),rr=tr,nr=/\s/;function ar(){return(ar=Object.assign?Object.assign.bind():function(t){for(var e=1;e=16?o--:o++;var f=li(l.trim()),g=vi(e,i,f);t&&t.cues&&t.cues.getCueById(g)||((a=new h(e,i,f)).id=g,a.line=d+1,a.align="left",a.position=10+Math.min(80,10*Math.floor(8*o/32)),u.push(a))}return t&&u.length&&(u.sort((function(t,e){return"auto"===t.line||"auto"===e.line?0:t.line>8&&e.line>8?e.line-t.line:t.line-e.line})),u.forEach((function(e){return N(t,e)}))),u}},enableWebVTT:!0,enableIMSC1:!0,enableCEA708Captions:!0,captionsTextTrack1Label:"English",captionsTextTrack1LanguageCode:"en",captionsTextTrack2Label:"Spanish",captionsTextTrack2LanguageCode:"es",captionsTextTrack3Label:"Unknown CC",captionsTextTrack3LanguageCode:"",captionsTextTrack4Label:"Unknown CC",captionsTextTrack4LanguageCode:"",renderTextTracksNatively:!0}),{},{subtitleStreamController:De,subtitleTrackController:Ce,timelineController:ki,audioStreamController:Te,audioTrackController:Se,emeController:Ui,cmcdController:Vi});function hr(t){var e=t.loader;e!==rr&&e!==qi?(l.b.log("[config]: Custom loader detected, cannot enable progressive streaming"),t.progressive=!1):function(){if(self.fetch&&self.AbortController&&self.ReadableStream&&self.Request)try{return new self.ReadableStream({}),!0}catch(t){}return!1}()&&(t.loader=rr,t.progressive=!0,t.enableSoftwareAES=!0,l.b.log("[config]: Progressive streaming enabled, using FetchLoader"))}function dr(t,e){for(var i=0;i=e)return r;return 0}},{key:"maxAutoLevel",get:function(){var t=this.levels,e=this.autoLevelCapping;return-1===e&&t&&t.length?t.length-1:e}},{key:"nextAutoLevel",get:function(){return Math.min(Math.max(this.abrController.nextAutoLevel,this.minAutoLevel),this.maxAutoLevel)},set:function(t){this.abrController.nextAutoLevel=Math.max(this.minAutoLevel,t)}},{key:"playingDate",get:function(){return this.streamController.currentProgramDateTime}},{key:"mainForwardBufferInfo",get:function(){return this.streamController.getMainFwdBufferInfo()}},{key:"audioTracks",get:function(){var t=this.audioTrackController;return t?t.audioTracks:[]}},{key:"audioTrack",get:function(){var t=this.audioTrackController;return t?t.audioTrack:-1},set:function(t){var e=this.audioTrackController;e&&(e.audioTrack=t)}},{key:"subtitleTracks",get:function(){var t=this.subtitleTrackController;return t?t.subtitleTracks:[]}},{key:"subtitleTrack",get:function(){var t=this.subtitleTrackController;return t?t.subtitleTrack:-1},set:function(t){var e=this.subtitleTrackController;e&&(e.subtitleTrack=t)}},{key:"media",get:function(){return this._media}},{key:"subtitleDisplay",get:function(){var t=this.subtitleTrackController;return!!t&&t.subtitleDisplay},set:function(t){var e=this.subtitleTrackController;e&&(e.subtitleDisplay=t)}},{key:"lowLatencyMode",get:function(){return this.config.lowLatencyMode},set:function(t){this.config.lowLatencyMode=t}},{key:"liveSyncPosition",get:function(){return this.latencyController.liveSyncPosition}},{key:"latency",get:function(){return this.latencyController.latency}},{key:"maxLatency",get:function(){return this.latencyController.maxLatency}},{key:"targetLatency",get:function(){return this.latencyController.targetLatency}},{key:"drift",get:function(){return this.latencyController.drift}},{key:"forceStartLoad",get:function(){return this.streamController.forceStartLoad}}])&&dr(e.prototype,i),r&&dr(e,r),Object.defineProperty(e,"prototype",{writable:!1}),t}();cr.defaultConfig=void 0}]).default})); //# sourceMappingURL=hls.min.js.map -// @license-end \ No newline at end of file +// @license-end From ae3ea2da7cb300eb9208ef7d34abfb51f06706ea Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 3 Nov 2022 22:04:34 -0600 Subject: [PATCH 27/92] HTTP compression (Reddit -> Libreddit -> client) (#612) Implements HTTP compression, between both Reddit and Libreddit and Libreddit and a web browser. Compression between Reddit and Libreddit is mandatory, whereas compression between Libreddit and a client is opt-in (client must specify a compressor in the Accept-Encoding header). Supported compressors are gzip and brotli. gzip support is ubiquitous, whereas brotli is supported by almost all modern browsers except Safari (iOS, iPhone, macOS), although Safari may support brotli in the future. Co-authored-by: Matthew E --- Cargo.lock | 137 ++++++++++++ Cargo.toml | 5 + src/client.rs | 52 ++++- src/server.rs | 579 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/utils.rs | 15 ++ 5 files changed, 762 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9937801..97739d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aho-corasick" version = "0.7.19" @@ -11,6 +17,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "askama" version = "0.11.1" @@ -109,6 +130,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bstr" version = "0.2.17" @@ -233,6 +275,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -398,6 +449,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "globset" version = "0.4.9" @@ -580,18 +642,41 @@ version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +[[package]] +name = "libflate" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05605ab2bce11bcfc0e9c635ff29ef8b2ea83f29be257ee7d730cac3ee373093" +dependencies = [ + "adler32", + "crc32fast", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a734c0493409afcd49deee13c006a04e3586b9761a03543c6272c9c51f2f5a" +dependencies = [ + "rle-decode-fast", +] + [[package]] name = "libreddit" version = "0.23.1" dependencies = [ "askama", "async-recursion", + "brotli", "cached", "clap", "cookie", "futures-lite", "hyper", "hyper-rustls", + "libflate", + "lipsum", "percent-encoding", "regex", "route-recognizer", @@ -603,6 +688,16 @@ dependencies = [ "url", ] +[[package]] +name = "lipsum" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8451846f1f337e44486666989fbce40be804da139d5a4477d6b88ece5dc69f4" +dependencies = [ + "rand", + "rand_chacha", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -756,6 +851,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + [[package]] name = "proc-macro2" version = "1.0.47" @@ -774,6 +875,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -815,6 +946,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "route-recognizer" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index adf135a..42b12db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,8 @@ tokio = { version = "1.21.2", features = ["full"] } time = "0.3.16" url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } +libflate = "1.2.0" +brotli = { version = "3.3.4", features = ["std"] } + +[dev-dependencies] +lipsum = "0.8.2" diff --git a/src/client.rs b/src/client.rs index da271dd..5c32335 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,9 +1,10 @@ use cached::proc_macro::cached; use futures_lite::{future::Boxed, FutureExt}; -use hyper::{body::Buf, client, Body, Request, Response, Uri}; +use hyper::{body, body::Buf, client, header, Body, Request, Response, Uri}; +use libflate::gzip; use percent_encoding::{percent_encode, CONTROLS}; use serde_json::Value; -use std::result::Result; +use std::{io, result::Result}; use crate::server::RequestExt; @@ -76,6 +77,7 @@ fn request(url: String, quarantine: bool) -> Boxed, String .header("User-Agent", format!("web:libreddit:{}", env!("CARGO_PKG_VERSION"))) .header("Host", "www.reddit.com") .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") + .header("Accept-Encoding", "gzip") // Reddit doesn't do brotli yet. .header("Accept-Language", "en-US,en;q=0.5") .header("Connection", "keep-alive") .header("Cookie", if quarantine { "_options=%7B%22pref_quarantine_optin%22%3A%20true%7D" } else { "" }) @@ -84,7 +86,7 @@ fn request(url: String, quarantine: bool) -> Boxed, String async move { match builder { Ok(req) => match client.request(req).await { - Ok(response) => { + Ok(mut response) => { if response.status().to_string().starts_with('3') { request( response @@ -100,7 +102,49 @@ fn request(url: String, quarantine: bool) -> Boxed, String ) .await } else { - Ok(response) + match response.headers().get(header::CONTENT_ENCODING) { + // Content not compressed. + None => Ok(response), + + // Content gzipped. + Some(hdr) => { + // Since we requested gzipped content, we expect + // to get back gzipped content. If we get + // back anything else, that's a problem. + if hdr.ne("gzip") { + return Err("Reddit response was encoded with an unsupported compressor".to_string()); + } + + // The body must be something that implements + // std::io::Read, hence the conversion to + // bytes::buf::Buf and then transformation into a + // Reader. + let mut decompressed: Vec; + { + let mut aggregated_body = match body::aggregate(response.body_mut()).await { + Ok(b) => b.reader(), + Err(e) => return Err(e.to_string()), + }; + + let mut decoder = match gzip::Decoder::new(&mut aggregated_body) { + Ok(decoder) => decoder, + Err(e) => return Err(e.to_string()), + }; + + decompressed = Vec::::new(); + match io::copy(&mut decoder, &mut decompressed) { + Ok(_) => {} + Err(e) => return Err(e.to_string()), + }; + } + + response.headers_mut().remove(header::CONTENT_ENCODING); + response.headers_mut().insert(header::CONTENT_LENGTH, decompressed.len().into()); + *(response.body_mut()) = Body::from(decompressed); + + Ok(response) + } + } } } Err(e) => Err(e.to_string()), diff --git a/src/server.rs b/src/server.rs index 979dbd7..c277b6b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,17 +1,80 @@ +use brotli::enc::{BrotliCompress, BrotliEncoderParams}; +use cached::proc_macro::cached; use cookie::Cookie; +use core::f64; use futures_lite::{future::Boxed, Future, FutureExt}; use hyper::{ - header::HeaderValue, + body, + body::HttpBody, + header, service::{make_service_fn, service_fn}, HeaderMap, }; use hyper::{Body, Method, Request, Response, Server as HyperServer}; +use libflate::gzip; use route_recognizer::{Params, Router}; -use std::{pin::Pin, result::Result}; +use std::{ + cmp::Ordering, + io, + pin::Pin, + result::Result, + str::{from_utf8, Split}, + string::ToString, +}; use time::Duration; +use crate::dbg_msg; + type BoxResponse = Pin, String>> + Send>>; +/// Compressors for the response Body, in ascending order of preference. +#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +enum CompressionType { + Passthrough, + Gzip, + Brotli, +} + +/// All browsers support gzip, so if we are given `Accept-Encoding: *`, deliver +/// gzipped-content. +/// +/// Brotli would be nice universally, but Safari (iOS, iPhone, macOS) reportedly +/// doesn't support it yet. +const DEFAULT_COMPRESSOR: CompressionType = CompressionType::Gzip; + +impl CompressionType { + /// Returns a `CompressionType` given a content coding + /// in [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.4) + /// format. + fn parse(s: &str) -> Option { + let c = match s { + // Compressors we support. + "gzip" => CompressionType::Gzip, + "br" => CompressionType::Brotli, + + // The wildcard means that we can choose whatever + // compression we prefer. In this case, use the + // default. + "*" => DEFAULT_COMPRESSOR, + + // Compressor not supported. + _ => return None, + }; + + Some(c) + } +} + +impl ToString for CompressionType { + fn to_string(&self) -> String { + match self { + CompressionType::Gzip => "gzip".to_string(), + CompressionType::Brotli => "br".to_string(), + _ => String::new(), + } + } +} + pub struct Route<'a> { router: &'a mut Router) -> BoxResponse>, path: String, @@ -97,7 +160,7 @@ impl ResponseExt for Response { } fn insert_cookie(&mut self, cookie: Cookie) { - if let Ok(val) = HeaderValue::from_str(&cookie.to_string()) { + if let Ok(val) = header::HeaderValue::from_str(&cookie.to_string()) { self.headers_mut().append("Set-Cookie", val); } } @@ -106,7 +169,7 @@ impl ResponseExt for Response { let mut cookie = Cookie::named(name); cookie.set_path("/"); cookie.set_max_age(Duration::seconds(1)); - if let Ok(val) = HeaderValue::from_str(&cookie.to_string()) { + if let Ok(val) = header::HeaderValue::from_str(&cookie.to_string()) { self.headers_mut().append("Set-Cookie", val); } } @@ -156,10 +219,11 @@ impl Server { // let shared_router = router.clone(); async move { Ok::<_, String>(service_fn(move |req: Request| { - let headers = default_headers.clone(); + let req_headers = req.headers().clone(); + let def_headers = default_headers.clone(); // Remove double slashes and decode encoded slashes - let mut path = req.uri().path().replace("//", "/").replace("%2F","/"); + let mut path = req.uri().path().replace("//", "/").replace("%2F", "/"); // Remove trailing slashes if path != "/" && path.ends_with('/') { @@ -176,26 +240,20 @@ impl Server { // Run the route's function let func = (found.handler().to_owned().to_owned())(parammed); async move { - let res: Result, String> = func.await; - // Add default headers to response - res.map(|mut response| { - response.headers_mut().extend(headers); - response - }) + match func.await { + Ok(mut res) => { + res.headers_mut().extend(def_headers); + let _ = compress_response(req_headers, &mut res).await; + + Ok(res) + } + Err(msg) => new_boilerplate(def_headers, req_headers, 500, Body::from(msg)).await, + } } .boxed() } // If there was a routing error - Err(e) => async move { - // Return a 404 error - let res: Result, String> = Ok(Response::builder().status(404).body(e.into()).unwrap_or_default()); - // Add default headers to response - res.map(|mut response| { - response.headers_mut().extend(headers); - response - }) - } - .boxed(), + Err(e) => async move { new_boilerplate(def_headers, req_headers, 404, e.into()).await }.boxed(), } })) } @@ -213,3 +271,480 @@ impl Server { server.boxed() } } + +/// Create a boilerplate Response for error conditions. This response will be +/// compressed if requested by client. +async fn new_boilerplate( + default_headers: HeaderMap, + req_headers: HeaderMap, + status: u16, + body: Body, +) -> Result, String> { + match Response::builder().status(status).body(body) { + Ok(mut res) => { + let _ = compress_response(req_headers, &mut res).await; + + res.headers_mut().extend(default_headers.clone()); + Ok(res) + } + Err(msg) => Err(msg.to_string()), + } +} + +/// Determines the desired compressor based on the Accept-Encoding header. +/// +/// This function will honor the [q-value](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values) +/// for each compressor. The q-value is an optional parameter, a decimal value +/// on \[0..1\], to order the compressors by preference. An Accept-Encoding value +/// with no q-values is also accepted. +/// +/// Here are [examples](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding#examples) +/// of valid Accept-Encoding headers. +/// +/// ```http +/// Accept-Encoding: gzip +/// Accept-Encoding: gzip, compress, br +/// Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1 +/// ``` +fn determine_compressor(accept_encoding: &str) -> Option { + if accept_encoding.is_empty() { + return None; + }; + + // Keep track of the compressor candidate based on both the client's + // preference and our own. Concrete examples: + // + // 1. "Accept-Encoding: gzip, br" => assuming we like brotli more than + // gzip, and the browser supports brotli, we choose brotli + // + // 2. "Accept-Encoding: gzip;q=0.8, br;q=0.3" => the client has stated a + // preference for gzip over brotli, so we choose gzip + // + // To do this, we need to define a struct which contains the requested + // requested compressor (abstracted as a CompressionType enum) and the + // q-value. If no q-value is defined for the compressor, we assume one of + // 1.0. We first compare compressor candidates by comparing q-values, and + // then CompressionTypes. We keep track of whatever is the greatest per our + // ordering. + + struct CompressorCandidate { + alg: CompressionType, + q: f64, + } + + impl Ord for CompressorCandidate { + fn cmp(&self, other: &Self) -> Ordering { + // Compare q-values. Break ties with the + // CompressionType values. + + match self.q.total_cmp(&other.q) { + Ordering::Equal => self.alg.cmp(&other.alg), + ord => ord, + } + } + } + + impl PartialOrd for CompressorCandidate { + fn partial_cmp(&self, other: &Self) -> Option { + // Guard against NAN, both on our end and on the other. + if self.q.is_nan() || other.q.is_nan() { + return None; + }; + + // f64 and CompressionType are ordered, except in the case + // where the f64 is NAN (which we checked against), so we + // can safely return a Some here. + Some(self.cmp(other)) + } + } + + impl PartialEq for CompressorCandidate { + fn eq(&self, other: &Self) -> bool { + (self.q == other.q) && (self.alg == other.alg) + } + } + + impl Eq for CompressorCandidate {} + + // This is the current candidate. + // + // Assmume no candidate so far. We do this by assigning the sentinel value + // of negative infinity to the q-value. If this value is negative infinity, + // that means there was no viable compressor candidate. + let mut cur_candidate = CompressorCandidate { + alg: CompressionType::Passthrough, + q: f64::NEG_INFINITY, + }; + + // This loop reads the requested compressors and keeps track of whichever + // one has the highest priority per our heuristic. + for val in accept_encoding.to_string().split(',') { + let mut q: f64 = 1.0; + + // The compressor and q-value (if the latter is defined) + // will be delimited by semicolons. + let mut spl: Split = val.split(';'); + + // Get the compressor. For example, in + // gzip;q=0.8 + // this grabs "gzip" in the string. It + // will further validate the compressor against the + // list of those we support. If it is not supported, + // we move onto the next one. + let compressor: CompressionType = match spl.next() { + // CompressionType::parse will return the appropriate enum given + // a string. For example, it will return CompressionType::Gzip + // when given "gzip". + Some(s) => match CompressionType::parse(s.trim()) { + Some(candidate) => candidate, + + // We don't support the requested compression algorithm. + None => continue, + }, + + // We should never get here, but I'm paranoid. + None => continue, + }; + + // Get the q-value. This might not be defined, in which case assume + // 1.0. + if let Some(s) = spl.next() { + if !(s.len() > 2 && s.starts_with("q=")) { + // If the q-value is malformed, the header is malformed, so + // abort. + return None; + } + + match s[2..].parse::() { + Ok(val) => { + if (0.0..=1.0).contains(&val) { + q = val; + } else { + // If the value is outside [0..1], header is malformed. + // Abort. + return None; + }; + } + Err(_) => { + // If this isn't a f64, then assume a malformed header + // value and abort. + return None; + } + } + }; + + // If new_candidate > cur_candidate, make new_candidate the new + // cur_candidate. But do this safely! It is very possible that + // someone gave us the string "NAN", which (&str).parse:: + // will happily translate to f64::NAN. + let new_candidate = CompressorCandidate { alg: compressor, q }; + if let Some(ord) = new_candidate.partial_cmp(&cur_candidate) { + if ord == Ordering::Greater { + cur_candidate = new_candidate; + } + }; + } + + if cur_candidate.q != f64::NEG_INFINITY { + Some(cur_candidate.alg) + } else { + None + } +} + +/// Compress the response body, if possible or desirable. The Body will be +/// compressed in place, and a new header Content-Encoding will be set +/// indicating the compression algorithm. +/// +/// This function deems Body eligible compression if and only if the following +/// conditions are met: +/// +/// 1. the HTTP client requests a compression encoding in the Content-Encoding +/// header (hence the need for the req_headers); +/// +/// 2. the content encoding corresponds to a compression algorithm we support; +/// +/// 3. the Media type in the Content-Type response header is text with any +/// subtype (e.g. text/plain) or application/json. +/// +/// compress_response returns Ok on successful compression, or if not all three +/// conditions above are met. It returns Err if there was a problem decoding +/// any header in either req_headers or res, but res will remain intact. +/// +/// This function logs errors to stderr, but only in debug mode. No information +/// is logged in release builds. +async fn compress_response(req_headers: HeaderMap, res: &mut Response) -> Result<(), String> { + // Check if the data is eligible for compression. + if let Some(hdr) = res.headers().get(header::CONTENT_TYPE) { + match from_utf8(hdr.as_bytes()) { + Ok(val) => { + let s = val.to_string(); + + // TODO: better determination of what is eligible for compression + if !(s.starts_with("text/") || s.starts_with("application/json")) { + return Ok(()); + }; + } + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + }; + } else { + // Response declares no Content-Type. Assume for simplicity that it + // cannot be compressed. + return Ok(()); + }; + + // Don't bother if the size of the size of the response body will fit + // within an IP frame (less the bytes that make up the TCP/IP and HTTP + // headers). + if res.body().size_hint().lower() < 1452 { + return Ok(()); + }; + + // Quick and dirty closure for extracting a header from the request and + // returning it as a &str. + let get_req_header = |k: header::HeaderName| -> Option<&str> { + match req_headers.get(k) { + Some(hdr) => match from_utf8(hdr.as_bytes()) { + Ok(val) => Some(val), + + #[cfg(debug_assertions)] + Err(e) => { + dbg_msg!(e); + None + } + + #[cfg(not(debug_assertions))] + Err(_) => None, + }, + None => None, + } + }; + + // Check to see which compressor is requested, and if we can use it. + let accept_encoding: &str = match get_req_header(header::ACCEPT_ENCODING) { + Some(val) => val, + None => return Ok(()), // Client requested no compression. + }; + + let compressor: CompressionType = match determine_compressor(accept_encoding) { + Some(c) => c, + None => return Ok(()), + }; + + // Get the body from the response. + let body_bytes: Vec = match body::to_bytes(res.body_mut()).await { + Ok(b) => b.to_vec(), + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + }; + + // Compress! + match compress_body(compressor, body_bytes) { + Ok(compressed) => { + // We get here iff the compression was successful. Replace the body + // with the compressed payload, and add the appropriate + // Content-Encoding header in the response. + res.headers_mut().insert(header::CONTENT_ENCODING, compressor.to_string().parse().unwrap()); + *(res.body_mut()) = Body::from(compressed); + } + + Err(e) => return Err(e), + } + + Ok(()) +} + +/// Compresses a `Vec` given a [`CompressionType`]. +/// +/// This is a helper function for [`compress_response`] and should not be +/// called directly. + +// I've chosen a TTL of 600 (== 10 minutes) since compression is +// computationally expensive and we don't want to be doing it often. This is +// larger than client::json's TTL, but that's okay, because if client::json +// returns a new serde_json::Value, body_bytes changes, so this function will +// execute again. +#[cached(size = 100, time = 600, result = true)] +fn compress_body(compressor: CompressionType, body_bytes: Vec) -> Result, String> { + // io::Cursor implements io::Read, required for our encoders. + let mut reader = io::Cursor::new(body_bytes); + + let compressed: Vec = match compressor { + CompressionType::Gzip => { + let mut gz: gzip::Encoder> = match gzip::Encoder::new(Vec::new()) { + Ok(gz) => gz, + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + }; + + match io::copy(&mut reader, &mut gz) { + Ok(_) => match gz.finish().into_result() { + Ok(compressed) => compressed, + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + }, + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + } + } + + CompressionType::Brotli => { + // We may want to make the compression parameters configurable + // in the future. For now, the defaults are sufficient. + let brotli_params = BrotliEncoderParams::default(); + + let mut compressed = Vec::::new(); + match BrotliCompress(&mut reader, &mut compressed, &brotli_params) { + Ok(_) => compressed, + Err(e) => { + dbg_msg!(e); + return Err(e.to_string()); + } + } + } + + // This arm is for any requested compressor for which we don't yet + // have an implementation. + _ => { + let msg = "unsupported compressor".to_string(); + return Err(msg); + } + }; + + Ok(compressed) +} + +#[cfg(test)] +mod tests { + use super::*; + use brotli::Decompressor as BrotliDecompressor; + use futures_lite::future::block_on; + use lipsum::lipsum; + use std::{boxed::Box, io}; + + #[test] + fn test_determine_compressor() { + // Single compressor given. + assert_eq!(determine_compressor("unsupported"), None); + assert_eq!(determine_compressor("gzip"), Some(CompressionType::Gzip)); + assert_eq!(determine_compressor("*"), Some(DEFAULT_COMPRESSOR)); + + // Multiple compressors. + assert_eq!(determine_compressor("gzip, br"), Some(CompressionType::Brotli)); + assert_eq!(determine_compressor("gzip;q=0.8, br;q=0.3"), Some(CompressionType::Gzip)); + assert_eq!(determine_compressor("br, gzip"), Some(CompressionType::Brotli)); + assert_eq!(determine_compressor("br;q=0.3, gzip;q=0.4"), Some(CompressionType::Gzip)); + + // Invalid q-values. + assert_eq!(determine_compressor("gzip;q=NAN"), None); + } + + #[test] + fn test_compress_response() { + // This macro generates an Accept-Encoding header value given any number of + // compressors. + macro_rules! ae_gen { + ($x:expr) => { + $x.to_string().as_str() + }; + + ($x:expr, $($y:expr),+) => { + format!("{}, {}", $x.to_string(), ae_gen!($($y),+)).as_str() + }; + } + + for accept_encoding in [ + "*", + ae_gen!(CompressionType::Gzip), + ae_gen!(CompressionType::Brotli, CompressionType::Gzip), + ae_gen!(CompressionType::Brotli), + ] { + // Determine what the expected encoding should be based on both the + // specific encodings we accept. + let expected_encoding: CompressionType = match determine_compressor(accept_encoding) { + Some(s) => s, + None => panic!("determine_compressor(accept_encoding) => None"), + }; + + // Build headers with our Accept-Encoding. + let mut req_headers = HeaderMap::new(); + req_headers.insert(header::ACCEPT_ENCODING, header::HeaderValue::from_str(accept_encoding).unwrap()); + + // Build test response. + let lorem_ipsum: String = lipsum(10000); + let expected_lorem_ipsum = Vec::::from(lorem_ipsum.as_str()); + let mut res = Response::builder() + .status(200) + .header(header::CONTENT_TYPE, "text/plain") + .body(Body::from(lorem_ipsum)) + .unwrap(); + + // Perform the compression. + if let Err(e) = block_on(compress_response(req_headers, &mut res)) { + panic!("compress_response(req_headers, &mut res) => Err(\"{}\")", e); + }; + + // If the content was compressed, we expect the Content-Encoding + // header to be modified. + assert_eq!( + res + .headers() + .get(header::CONTENT_ENCODING) + .unwrap_or_else(|| panic!("missing content-encoding header")) + .to_str() + .unwrap_or_else(|_| panic!("failed to convert Content-Encoding header::HeaderValue to String")), + expected_encoding.to_string() + ); + + // Decompress body and make sure it's equal to what we started + // with. + // + // In the case of no compression, just make sure the "new" body in + // the Response is the same as what with which we start. + let body_vec = match block_on(body::to_bytes(res.body_mut())) { + Ok(b) => b.to_vec(), + Err(e) => panic!("{}", e), + }; + + if expected_encoding == CompressionType::Passthrough { + assert!(body_vec.eq(&expected_lorem_ipsum)); + continue; + } + + // This provides an io::Read for the underlying body. + let mut body_cursor: io::Cursor> = io::Cursor::new(body_vec); + + // Match the appropriate decompresor for the given + // expected_encoding. + let mut decoder: Box = match expected_encoding { + CompressionType::Gzip => match gzip::Decoder::new(&mut body_cursor) { + Ok(dgz) => Box::new(dgz), + Err(e) => panic!("{}", e), + }, + + CompressionType::Brotli => Box::new(BrotliDecompressor::new(body_cursor, expected_lorem_ipsum.len())), + + _ => panic!("no decompressor for {}", expected_encoding.to_string()), + }; + + let mut decompressed = Vec::::new(); + match io::copy(&mut decoder, &mut decompressed) { + Ok(_) => {} + Err(e) => panic!("{}", e), + }; + + assert!(decompressed.eq(&expected_lorem_ipsum)); + } + } +} diff --git a/src/utils.rs b/src/utils.rs index 2691d16..42243d5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -13,6 +13,21 @@ use std::str::FromStr; use time::{macros::format_description, Duration, OffsetDateTime}; use url::Url; +/// Write a message to stderr on debug mode. This function is a no-op on +/// release code. +#[macro_export] +macro_rules! dbg_msg { + ($x:expr) => { + #[cfg(debug_assertions)] + eprintln!("{}:{}: {}", file!(), line!(), $x.to_string()) + }; + + ($($x:expr),+) => { + #[cfg(debug_assertions)] + dbg_msg!(format!($($x),+)) + }; +} + // Post flair with content, background color and foreground color pub struct Flair { pub flair_parts: Vec, From 8348e207247bed53ab822dc366988550c263098b Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 3 Nov 2022 22:08:36 -0600 Subject: [PATCH 28/92] Use permalink offered by Reddit (fixes #613). (#614) --- templates/post.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/post.html b/templates/post.html index 227d7fc..e447eb3 100644 --- a/templates/post.html +++ b/templates/post.html @@ -114,8 +114,8 @@
{{ post.score.0 }} Upvotes
@@ -138,7 +138,7 @@ {% for c in comments -%}
{% if single_thread %} -

View all comments

+

View all comments

{% if c.parent_kind == "t1" %}

Show parent comments

{% endif %} From c0e37443ae0022284c5af80cc88898597d527d13 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Thu, 3 Nov 2022 21:30:35 -0700 Subject: [PATCH 29/92] Allow the spoilering of links (fixes #610) --- static/style.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/static/style.css b/static/style.css index d8bebff..1552c22 100644 --- a/static/style.css +++ b/static/style.css @@ -1182,16 +1182,21 @@ input[type="submit"] { color: var(--accent); } -.md .md-spoiler-text { +.md .md-spoiler-text, .md-spoiler-text a { background: var(--highlighted); color: transparent; } -.md .md-spoiler-text:hover { +.md-spoiler-text:hover { background: var(--foreground); color: var(--text); } +.md-spoiler-text:hover a { + background: var(--foreground); + color: var(--accent); +} + .md li { margin: 10px 0; } .toc_child { list-style: none; } From 377634841ccfba929952a9d3ce63f00cc61a0aa6 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Thu, 3 Nov 2022 21:31:32 -0700 Subject: [PATCH 30/92] Upgrade to v0.23.2 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97739d5..fd537f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.23.1" +version = "0.23.2" dependencies = [ "askama", "async-recursion", @@ -769,9 +769,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", diff --git a/Cargo.toml b/Cargo.toml index 42b12db..da1ee8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.23.1" +version = "0.23.2" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 584cd4aac1123a40e08b30f68fc3b28f702453e9 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 3 Nov 2022 23:08:03 -0600 Subject: [PATCH 31/92] Add DoomOne theme, c/o Tildemaster (#611) --- static/themes/doomone.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 static/themes/doomone.css diff --git a/static/themes/doomone.css b/static/themes/doomone.css new file mode 100644 index 0000000..27cb06f --- /dev/null +++ b/static/themes/doomone.css @@ -0,0 +1,13 @@ +.doomone { + --accent: #51afef; + --green: #00a229; + --text: #bbc2cf; + --foreground: #3d4148; + --background: #282c34; + --outside: #52565c; + --post: #24272e; + --panel-border: 2px solid #52565c; + --highlighted: #686b70; + --visited: #969692; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} From c6487799edd93d1b26de9b8c516cd7c86e5303de Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 5 Nov 2022 02:29:04 -0600 Subject: [PATCH 32/92] Redirect /:id to canonical URL for post. (#617) * Redirect /:id to canonical URL for post. This implements redirection of `/:id` (a short-form URL to a post) to the post's canonical URL. Libreddit issues a `HEAD /:id` to Reddit to get the canonical URL, and on success will send an HTTP 302 to a client with the canonical URL set in as the value of the `Location:` header. This also implements support for short IDs for non-ASCII posts, c/o spikecodes. Co-authored-by: spikecodes <19519553+spikecodes@users.noreply.github.com> --- src/client.rs | 182 +++++++++++++++++++++++++++++++++++--------------- src/main.rs | 31 ++++++--- src/utils.rs | 5 +- 3 files changed, 152 insertions(+), 66 deletions(-) diff --git a/src/client.rs b/src/client.rs index 5c32335..92b5529 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,13 +1,59 @@ use cached::proc_macro::cached; use futures_lite::{future::Boxed, FutureExt}; -use hyper::{body, body::Buf, client, header, Body, Request, Response, Uri}; +use hyper::{body, body::Buf, client, header, Body, Method, Request, Response, Uri}; use libflate::gzip; use percent_encoding::{percent_encode, CONTROLS}; use serde_json::Value; use std::{io, result::Result}; +use crate::dbg_msg; use crate::server::RequestExt; +const REDDIT_URL_BASE: &str = "https://www.reddit.com"; + +/// Gets the canonical path for a resource on Reddit. This is accomplished by +/// making a `HEAD` request to Reddit at the path given in `path`. +/// +/// This function returns `Ok(Some(path))`, where `path`'s value is identical +/// to that of the value of the argument `path`, if Reddit responds to our +/// `HEAD` request with a 2xx-family HTTP code. It will also return an +/// `Ok(Some(String))` if Reddit responds to our `HEAD` request with a +/// `Location` header in the response, and the HTTP code is in the 3xx-family; +/// the `String` will contain the path as reported in `Location`. The return +/// value is `Ok(None)` if Reddit responded with a 3xx, but did not provide a +/// `Location` header. An `Err(String)` is returned if Reddit responds with a +/// 429, or if we were unable to decode the value in the `Location` header. +#[cached(size = 1024, time = 600, result = true)] +pub async fn canonical_path(path: String) -> Result, String> { + let res = reddit_head(path.clone(), true).await?; + + if res.status() == 429 { + return Err("Too many requests.".to_string()); + }; + + // If Reddit responds with a 2xx, then the path is already canonical. + if res.status().to_string().starts_with('2') { + return Ok(Some(path)); + } + + // If Reddit responds with anything other than 3xx (except for the 2xx as + // above), return a None. + if !res.status().to_string().starts_with('3') { + return Ok(None); + } + + Ok( + res + .headers() + .get(header::LOCATION) + .map(|val| percent_encode(val.as_bytes(), CONTROLS) + .to_string() + .trim_start_matches(REDDIT_URL_BASE) + .to_string() + ), + ) +} + pub async fn proxy(req: Request, format: &str) -> Result, String> { let mut url = format!("{}?{}", format, req.uri().query().unwrap_or_default()); @@ -63,21 +109,39 @@ async fn stream(url: &str, req: &Request) -> Result, String .map_err(|e| e.to_string()) } -fn request(url: String, quarantine: bool) -> Boxed, String>> { +/// Makes a GET request to Reddit at `path`. By default, this will honor HTTP +/// 3xx codes Reddit returns and will automatically redirect. +fn reddit_get(path: String, quarantine: bool) -> Boxed, String>> { + request(&Method::GET, path, true, quarantine) +} + +/// Makes a HEAD request to Reddit at `path`. This will not follow redirects. +fn reddit_head(path: String, quarantine: bool) -> Boxed, String>> { + request(&Method::HEAD, path, false, quarantine) +} + +/// Makes a request to Reddit. If `redirect` is `true`, request_with_redirect +/// will recurse on the URL that Reddit provides in the Location HTTP header +/// in its response. +fn request(method: &'static Method, path: String, redirect: bool, quarantine: bool) -> Boxed, String>> { + // Build Reddit URL from path. + let url = format!("{}{}", REDDIT_URL_BASE, path); + // Prepare the HTTPS connector. let https = hyper_rustls::HttpsConnectorBuilder::new().with_native_roots().https_or_http().enable_http1().build(); // Construct the hyper client from the HTTPS connector. let client: client::Client<_, hyper::Body> = client::Client::builder().build(https); - // Build request + // Build request to Reddit. When making a GET, request gzip compression. + // (Reddit doesn't do brotli yet.) let builder = Request::builder() - .method("GET") + .method(method) .uri(&url) .header("User-Agent", format!("web:libreddit:{}", env!("CARGO_PKG_VERSION"))) .header("Host", "www.reddit.com") .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") - .header("Accept-Encoding", "gzip") // Reddit doesn't do brotli yet. + .header("Accept-Encoding", if method == Method::GET { "gzip" } else { "identity" }) .header("Accept-Language", "en-US,en;q=0.5") .header("Connection", "keep-alive") .header("Cookie", if quarantine { "_options=%7B%22pref_quarantine_optin%22%3A%20true%7D" } else { "" }) @@ -87,8 +151,15 @@ fn request(url: String, quarantine: bool) -> Boxed, String match builder { Ok(req) => match client.request(req).await { Ok(mut response) => { + // Reddit may respond with a 3xx. Decide whether or not to + // redirect based on caller params. if response.status().to_string().starts_with('3') { - request( + if !redirect { + return Ok(response); + }; + + return request( + method, response .headers() .get("Location") @@ -98,56 +169,64 @@ fn request(url: String, quarantine: bool) -> Boxed, String }) .unwrap_or_default() .to_string(), + true, quarantine, ) - .await - } else { - match response.headers().get(header::CONTENT_ENCODING) { - // Content not compressed. - None => Ok(response), + .await; + }; - // Content gzipped. - Some(hdr) => { - // Since we requested gzipped content, we expect - // to get back gzipped content. If we get - // back anything else, that's a problem. - if hdr.ne("gzip") { - return Err("Reddit response was encoded with an unsupported compressor".to_string()); - } + match response.headers().get(header::CONTENT_ENCODING) { + // Content not compressed. + None => Ok(response), - // The body must be something that implements - // std::io::Read, hence the conversion to - // bytes::buf::Buf and then transformation into a - // Reader. - let mut decompressed: Vec; - { - let mut aggregated_body = match body::aggregate(response.body_mut()).await { - Ok(b) => b.reader(), - Err(e) => return Err(e.to_string()), - }; - - let mut decoder = match gzip::Decoder::new(&mut aggregated_body) { - Ok(decoder) => decoder, - Err(e) => return Err(e.to_string()), - }; - - decompressed = Vec::::new(); - match io::copy(&mut decoder, &mut decompressed) { - Ok(_) => {} - Err(e) => return Err(e.to_string()), - }; - } - - response.headers_mut().remove(header::CONTENT_ENCODING); - response.headers_mut().insert(header::CONTENT_LENGTH, decompressed.len().into()); - *(response.body_mut()) = Body::from(decompressed); - - Ok(response) + // Content encoded (hopefully with gzip). + Some(hdr) => { + match hdr.to_str() { + Ok(val) => match val { + "gzip" => {} + "identity" => return Ok(response), + _ => return Err("Reddit response was encoded with an unsupported compressor".to_string()), + }, + Err(_) => return Err("Reddit response was invalid".to_string()), } + + // We get here if the body is gzip-compressed. + + // The body must be something that implements + // std::io::Read, hence the conversion to + // bytes::buf::Buf and then transformation into a + // Reader. + let mut decompressed: Vec; + { + let mut aggregated_body = match body::aggregate(response.body_mut()).await { + Ok(b) => b.reader(), + Err(e) => return Err(e.to_string()), + }; + + let mut decoder = match gzip::Decoder::new(&mut aggregated_body) { + Ok(decoder) => decoder, + Err(e) => return Err(e.to_string()), + }; + + decompressed = Vec::::new(); + if let Err(e) = io::copy(&mut decoder, &mut decompressed) { + return Err(e.to_string()); + }; + } + + response.headers_mut().remove(header::CONTENT_ENCODING); + response.headers_mut().insert(header::CONTENT_LENGTH, decompressed.len().into()); + *(response.body_mut()) = Body::from(decompressed); + + Ok(response) } } } - Err(e) => Err(e.to_string()), + Err(e) => { + dbg_msg!("{} {}: {}", method, path, e); + + Err(e.to_string()) + } }, Err(_) => Err("Post url contains non-ASCII characters".to_string()), } @@ -158,9 +237,6 @@ fn request(url: String, quarantine: bool) -> Boxed, String // Make a request to a Reddit API and parse the JSON response #[cached(size = 100, time = 30, result = true)] pub async fn json(path: String, quarantine: bool) -> Result { - // Build Reddit url from path - let url = format!("https://www.reddit.com{}", path); - // Closure to quickly build errors let err = |msg: &str, e: String| -> Result { // eprintln!("{} - {}: {}", url, msg, e); @@ -168,7 +244,7 @@ pub async fn json(path: String, quarantine: bool) -> Result { }; // Fetch the url... - match request(url.clone(), quarantine).await { + match reddit_get(path.clone(), quarantine).await { Ok(response) => { let status = response.status(); @@ -186,7 +262,7 @@ pub async fn json(path: String, quarantine: bool) -> Result { .as_str() .unwrap_or_else(|| { json["message"].as_str().unwrap_or_else(|| { - eprintln!("{} - Error parsing reddit error", url); + eprintln!("{}{} - Error parsing reddit error", REDDIT_URL_BASE, path); "Error parsing reddit error" }) }) diff --git a/src/main.rs b/src/main.rs index 4ce4a96..8592e3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use futures_lite::FutureExt; use hyper::{header::HeaderValue, Body, Request, Response}; mod client; -use client::proxy; +use client::{canonical_path, proxy}; use server::RequestExt; use utils::{error, redirect, ThemeAssets}; @@ -259,9 +259,6 @@ async fn main() { app.at("/r/:sub/:sort").get(|r| subreddit::community(r).boxed()); - // Comments handler - app.at("/comments/:id").get(|r| post::item(r).boxed()); - // Front page app.at("/").get(|r| subreddit::community(r).boxed()); @@ -279,13 +276,25 @@ async fn main() { // Handle about pages app.at("/about").get(|req| error(req, "About pages aren't added yet".to_string()).boxed()); - app.at("/:id").get(|req: Request| match req.param("id").as_deref() { - // Sort front page - Some("best" | "hot" | "new" | "top" | "rising" | "controversial") => subreddit::community(req).boxed(), - // Short link for post - Some(id) if id.len() > 4 && id.len() < 7 => post::item(req).boxed(), - // Error message for unknown pages - _ => error(req, "Nothing here".to_string()).boxed(), + app.at("/:id").get(|req: Request| { + Box::pin(async move { + match req.param("id").as_deref() { + // Sort front page + Some("best" | "hot" | "new" | "top" | "rising" | "controversial") => subreddit::community(req).await, + + // Short link for post + Some(id) if (5..7).contains(&id.len()) => match canonical_path(format!("/{}", id)).await { + Ok(path_opt) => match path_opt { + Some(path) => Ok(redirect(path)), + None => error(req, "Post ID is invalid. It may point to a post on a community that has been banned.").await, + }, + Err(e) => error(req, e).await, + }, + + // Error message for unknown pages + _ => error(req, "Nothing here".to_string()).await, + } + }) }); // Default service in case no routes match diff --git a/src/utils.rs b/src/utils.rs index 42243d5..8e738ed 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -716,10 +716,11 @@ pub fn redirect(path: String) -> Response { .unwrap_or_default() } -pub async fn error(req: Request, msg: String) -> Result, String> { +/// Renders a generic error landing page. +pub async fn error(req: Request, msg: impl ToString) -> Result, String> { let url = req.uri().to_string(); let body = ErrorTemplate { - msg, + msg: msg.to_string(), prefs: Preferences::new(req), url, } From bfe03578f0fd0dc6301ee92737a33d75060c6c93 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 5 Nov 2022 13:25:12 -0600 Subject: [PATCH 33/92] Update Instances section in README.md. --- README.md | 73 +------------------------------------------------------ 1 file changed, 1 insertion(+), 72 deletions(-) diff --git a/README.md b/README.md index 988e896..c262cc7 100644 --- a/README.md +++ b/README.md @@ -29,80 +29,9 @@ I appreciate any donations! Your support allows me to continue developing Libred # Instances -Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new) to have your [selfhosted instance](#deployment) listed here! - ๐Ÿ”— **Want to automatically redirect Reddit links to Libreddit? Use [LibRedirect](https://github.com/libredirect/libredirect) or [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect)!** -| Website | Country | Cloudflare | -|-|-|-| -| [libredd.it](https://libredd.it) (official) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.spike.codes](https://libreddit.spike.codes) (official) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.dothq.co](https://libreddit.dothq.co) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | -| [reddit.invak.id](https://reddit.invak.id) | ๐Ÿ‡ง๐Ÿ‡ฌ BG | | -| [lr.riverside.rocks](https://lr.riverside.rocks) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.strongthany.cc](https://libreddit.strongthany.cc) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.privacy.com.de](https://libreddit.privacy.com.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [libreddit.domain.glass](https://libreddit.domain.glass) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | -| [r.nf](https://r.nf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [lr.mint.lgbt](https://lr.mint.lgbt) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.intent.cool](https://libreddit.intent.cool) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.drivet.xyz](https://libreddit.drivet.xyz) | ๐Ÿ‡ต๐Ÿ‡ฑ PL | | -| [libreddit.de](https://libreddit.de) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [libreddit.pussthecat.org](https://libreddit.pussthecat.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [libreddit.mutahar.rocks](https://libreddit.mutahar.rocks) | ๐Ÿ‡ซ๐Ÿ‡ท FR | | -| [libreddit.northboot.xyz](https://libreddit.northboot.xyz) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [leddit.xyz](https://leddit.xyz) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [de.leddit.xyz](https://de.leddit.xyz) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [lr.cowfee.moe](https://lr.cowfee.moe) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.hu](https://libreddit.hu) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | โœ… | -| [libreddit.totaldarkness.net](https://libreddit.totaldarkness.net) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.esmailelbob.xyz](https://libreddit.esmailelbob.xyz) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [lr.vern.cc](https://lr.vern.cc) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.nl](https://libreddit.nl) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | -| [lr.stilic.ml](https://lr.stilic.ml) | ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | -| [reddi.tk](https://reddi.tk) | ๐Ÿ‡บ๐Ÿ‡ธ US | โœ… | -| [libreddit.bus-hit.me](https://libreddit.bus-hit.me) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [r.walkx.org](https://r.walkx.org) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | โœ… | -| [libreddit.kylrth.com](https://libreddit.kylrth.com) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.yonalee.eu](https://libreddit.yonalee.eu) | ๐Ÿ‡ฑ๐Ÿ‡บ LU | โœ… | -| [libreddit.winscloud.net](https://libreddit.winscloud.net) | ๐Ÿ‡น๐Ÿ‡ญ TH | โœ… | -| [libreddit.tiekoetter.com](https://libreddit.tiekoetter.com) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [reddit.rtrace.io](https://reddit.rtrace.io) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [libreddit.lunar.icu](https://libreddit.lunar.icu) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [libreddit.privacydev.net](https://libreddit.privacydev.net) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.notyourcomputer.net](https://libreddit.notyourcomputer.net) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [r.ahwx.org](https://r.ahwx.org) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | โœ… | -| [bob.fr.to](https://bob.fr.to) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [reddit.beparanoid.de](https://reddit.beparanoid.de) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | -| [libreddit.dcs0.hu](https://libreddit.dcs0.hu) | ๐Ÿ‡ญ๐Ÿ‡บ HU | | -| [reddit.dr460nf1r3.org](https://reddit.dr460nf1r3.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [rd.jae.su](https://rd.jae.su) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | -| [libreddit.mha.fi](https://libreddit.mha.fi) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | -| [libreddit.foss.wtf](https://libreddit.foss.wtf) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [libreddit.encrypted-data.xyz](https://libreddit.encrypted-data.xyz)| ๐Ÿ‡ซ๐Ÿ‡ท FR | โœ… | -| [libreddit.eu.org](https://libreddit.eu.org)| ๐Ÿ‡ฎ๐Ÿ‡ช IE | โœ… | -| [l.opnxng.com](https://l.opnxng.com)| ๐Ÿ‡ธ๐Ÿ‡ฌ SG | | -| [libreddit.cachyos.org](https://libreddit.cachyos.org) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | โœ… | -| [libreddit.oxymagnesium.com](https://libreddit.oxymagnesium.com) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | ๐Ÿ‡ฎ๐Ÿ‡ณ IN | | -| [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | ๐Ÿ‡ณ๐Ÿ‡ฑ NL | | -| [liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion](http://liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion](http://kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [ecue64ybzvn6vjzl37kcsnwt4ycmbsyf74nbttyg7rkc3t3qwnj7mcyd.onion](http://ecue64ybzvn6vjzl37kcsnwt4ycmbsyf74nbttyg7rkc3t3qwnj7mcyd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [ledditqo2mxfvlgobxnlhrkq4dh34jss6evfkdkb2thlvy6dn4f4gpyd.onion](http://ledditqo2mxfvlgobxnlhrkq4dh34jss6evfkdkb2thlvy6dn4f4gpyd.onion) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libredoxhxwnmsb6dvzzd35hmgzmawsq5i764es7witwhddvpc2razid.onion](http://libredoxhxwnmsb6dvzzd35hmgzmawsq5i764es7witwhddvpc2razid.onion) | ๐Ÿ‡บ๐Ÿ‡ธ US | | -| [libreddit.2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion](http://libreddit.2syis2nnyytz6jnusnjurva4swlaizlnleiks5mjp46phuwjbdjqwgqd.onion) | ๐Ÿ‡ช๐Ÿ‡ฌ EG | | -| [ol5begilptoou34emq2sshf3may3hlblvipdjtybbovpb7c7zodxmtqd.onion](http://ol5begilptoou34emq2sshf3may3hlblvipdjtybbovpb7c7zodxmtqd.onion) | ๐Ÿ‡ฉ๐Ÿ‡ช DE | | -| [lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion](http://lbrdtjaj7567ptdd4rv74lv27qhxfkraabnyphgcvptl64ijx2tijwid.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [libreddit.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion](http://libreddit.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -| [reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion](http://reddit.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion) | ๐Ÿ‡จ๐Ÿ‡ญ CH | | -| [inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion](http://inz6tbezfwzexva6dize4cqraj2tjdhygxabmcgysccesvw2pybzhbyd.onion) | ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | -| [libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion](http://libreddit.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion/)| ๐Ÿ‡ซ๐Ÿ‡ฎ FI | | -| [lr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion](http://lr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/) | ๐Ÿ‡จ๐Ÿ‡ฆ CA | | -A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare.com). The checkmark will not be listed for a site that uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website. +An up-to-date list of instances is maintained in the [libreddit-instances](https://github.com/libreddit/libreddit-instances) repo, in the form of [a machine-readable JSON](https://github.com/libreddit/libreddit-instances/blob/master/instances.json). To contribute your [self-hosted instance](#deployment) to the list, see the [libreddit-instances README](https://github.com/libreddit/libreddit-instances/blob/master/README.md). --- From cc27dc2a2684831559f8008f02d3367a2cf1b341 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 5 Nov 2022 20:50:42 -0600 Subject: [PATCH 34/92] Update README.md to point to markdown instances list. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c262cc7..afb0de8 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ I appreciate any donations! Your support allows me to continue developing Libred ๐Ÿ”— **Want to automatically redirect Reddit links to Libreddit? Use [LibRedirect](https://github.com/libredirect/libredirect) or [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect)!** -An up-to-date list of instances is maintained in the [libreddit-instances](https://github.com/libreddit/libreddit-instances) repo, in the form of [a machine-readable JSON](https://github.com/libreddit/libreddit-instances/blob/master/instances.json). To contribute your [self-hosted instance](#deployment) to the list, see the [libreddit-instances README](https://github.com/libreddit/libreddit-instances/blob/master/README.md). +[Follow this link](https://github.com/libreddit/libreddit-instances/blob/master/instances.md) for an up-to-date table of instances in markdown format. This list is also available as [a machine-readable JSON](https://github.com/libreddit/libreddit-instances/blob/master/instances.json). + +Both files are part of the [libreddit-instances](https://github.com/libreddit/libreddit-instances) repository. To contribute your [self-hosted instance](#deployment) to the list, see the [libreddit-instances README](https://github.com/libreddit/libreddit-instances/blob/master/README.md). --- From 371b7b2635e0adb9f92d6e74e35b11e6d7d2ab33 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 5 Nov 2022 21:24:16 -0600 Subject: [PATCH 35/92] Update Libreddit GitHub links. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index afb0de8..9e23c8f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Both files are part of the [libreddit-instances](https://github.com/libreddit/li # About -Find Libreddit on ๐Ÿ’ฌ [Matrix](https://matrix.to/#/#libreddit:kde.org), ๐Ÿ‹ [Docker](https://hub.docker.com/r/spikecodes/libreddit), :octocat: [GitHub](https://github.com/spikecodes/libreddit), and ๐ŸฆŠ [GitLab](https://gitlab.com/spikecodes/libreddit). +Find Libreddit on ๐Ÿ’ฌ [Matrix](https://matrix.to/#/#libreddit:kde.org), ๐Ÿ‹ [Docker](https://hub.docker.com/r/spikecodes/libreddit), :octocat: [GitHub](https://github.com/libreddit/libreddit), and ๐ŸฆŠ [GitLab](https://gitlab.com/spikecodes/libreddit). ## Built with @@ -51,7 +51,7 @@ Find Libreddit on ๐Ÿ’ฌ [Matrix](https://matrix.to/#/#libreddit:kde.org), ๐Ÿ‹ [D ## Info Libreddit hopes to provide an easier way to browse Reddit, without the ads, trackers, and bloat. Libreddit was inspired by other alternative front-ends to popular services such as [Invidious](https://github.com/iv-org/invidious) for YouTube, [Nitter](https://github.com/zedeus/nitter) for Twitter, and [Bibliogram](https://sr.ht/~cadence/bibliogram/) for Instagram. -Libreddit currently implements most of Reddit's (signed-out) functionalities but still lacks [a few features](https://github.com/spikecodes/libreddit/issues). +Libreddit currently implements most of Reddit's (signed-out) functionalities but still lacks [a few features](https://github.com/libreddit/libreddit/issues). ## How does it compare to Teddit? @@ -162,14 +162,14 @@ yay -S libreddit-git ## 4) GitHub Releases -If you're on Linux and none of these methods work for you, you can grab a Linux binary from [the newest release](https://github.com/spikecodes/libreddit/releases/latest). +If you're on Linux and none of these methods work for you, you can grab a Linux binary from [the newest release](https://github.com/libreddit/libreddit/releases/latest). ## 5) Replit/Heroku/Glitch **Note:** These are free hosting options but they are *not* private and will monitor server usage to prevent abuse. If you need a free and easy setup, this method may work best for you. -Run on Repl.it -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/spikecodes/libreddit) +Run on Repl.it +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/libreddit/libreddit) [![Remix on Glitch](https://cdn.glitch.com/2703baf2-b643-4da7-ab91-7ee2a2d00b5b%2Fremix-button-v2.svg)](https://glitch.com/edit/#!/remix/libreddit) --- @@ -211,7 +211,7 @@ LIBREDDIT_DEFAULT_WIDE=on LIBREDDIT_DEFAULT_THEME=dark libreddit -r ## Proxying using NGINX -**NOTE** If you're [proxying Libreddit through an NGINX Reverse Proxy](https://github.com/spikecodes/libreddit/issues/122#issuecomment-782226853), add +**NOTE** If you're [proxying Libreddit through an NGINX Reverse Proxy](https://github.com/libreddit/libreddit/issues/122#issuecomment-782226853), add ```nginx proxy_http_version 1.1; ``` @@ -239,7 +239,7 @@ Before=nginx.service ## Building ``` -git clone https://github.com/spikecodes/libreddit +git clone https://github.com/libreddit/libreddit cd libreddit cargo run ``` From d4ca376e8dea7d97fe1f9ebb8d3cbfcbaebac75b Mon Sep 17 00:00:00 2001 From: Matthew E Date: Sun, 6 Nov 2022 01:51:56 -0400 Subject: [PATCH 36/92] Add format_url tests (#615) --- src/utils.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 8e738ed..a458cd8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -732,8 +732,7 @@ pub async fn error(req: Request, msg: impl ToString) -> Resulthttps://www.reddit.com/r/linux_gaming/comments/x/just_a_test/"# ) } + + #[test] + fn test_format_url() { + assert_eq!(format_url("https://a.thumbs.redditmedia.com/XYZ.jpg"), "/thumb/a/XYZ.jpg"); + assert_eq!(format_url("https://emoji.redditmedia.com/a/b"), "/emoji/a/b"); + + assert_eq!( + format_url("https://external-preview.redd.it/foo.jpg?auto=webp&s=bar"), + "/preview/external-pre/foo.jpg?auto=webp&s=bar" + ); + + assert_eq!(format_url("https://i.redd.it/foobar.jpg"), "/img/foobar.jpg"); + assert_eq!( + format_url("https://preview.redd.it/qwerty.jpg?auto=webp&s=asdf"), + "/preview/pre/qwerty.jpg?auto=webp&s=asdf" + ); + assert_eq!(format_url("https://v.redd.it/foo/DASH_360.mp4?source=fallback"), "/vid/foo/360.mp4"); + assert_eq!( + format_url("https://v.redd.it/foo/HLSPlaylist.m3u8?a=bar&v=1&f=sd"), + "/hls/foo/HLSPlaylist.m3u8?a=bar&v=1&f=sd" + ); + assert_eq!(format_url("https://www.redditstatic.com/gold/awards/icon/icon.png"), "/static/gold/awards/icon/icon.png"); + + assert_eq!(format_url(""), ""); + assert_eq!(format_url("self"), ""); + assert_eq!(format_url("default"), ""); + assert_eq!(format_url("nsfw"), ""); + assert_eq!(format_url("spoiler"), ""); + } } From 5c366e14a32649506187dd0e0c0164ce93dad0d7 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 15 Oct 2022 13:08:47 -0600 Subject: [PATCH 37/92] Add CREDITS file and script to generate. (Resolves ferritreader/ferrit#33) --- CREDITS | 77 ++++++++++++++++++++++++++++++++++++++++++ scripts/gen-credits.sh | 15 ++++++++ 2 files changed, 92 insertions(+) create mode 100644 CREDITS create mode 100755 scripts/gen-credits.sh diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..2bfb498 --- /dev/null +++ b/CREDITS @@ -0,0 +1,77 @@ +5trongthany <65565784+5trongthany@users.noreply.github.com> +674Y3r <87250374+674Y3r@users.noreply.github.com> +accountForIssues <52367365+accountForIssues@users.noreply.github.com> +Adrian Lebioda +alefvanoon <53198048+alefvanoon@users.noreply.github.com> +alyaeanyx +AndreVuillemot160 <84594011+AndreVuillemot160@users.noreply.github.com> +Andrew Kaufman <57281817+andrew-kaufman@users.noreply.github.com> +Artemis <51862164+artemislena@users.noreply.github.com> +arthomnix <35371030+arthomnix@users.noreply.github.com> +Arya K <73596856+gi-yt@users.noreply.github.com> +Austin Huang +Basti +Ben Smith <37027883+smithbm2316@users.noreply.github.com> +BobIsMyManager +curlpipe <11898833+curlpipe@users.noreply.github.com> +dacousb <53299044+dacousb@users.noreply.github.com> +Daniel Valentine +dbrennand <52419383+dbrennand@users.noreply.github.com> +Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com> +Dyras +Edward <101938856+EdwardLangdon@users.noreply.github.com> +erdnaxe +Esmail EL BoB +FireMasterK <20838718+FireMasterK@users.noreply.github.com> +George Roubos +git-bruh +guaddy <67671414+guaddy@users.noreply.github.com> +Harsh Mishra +igna +imabritishcow +Josiah <70736638+fres7h@users.noreply.github.com> +JPyke3 +Kavin <20838718+FireMasterK@users.noreply.github.com> +Kazi +Kieran <42723993+EnderDev@users.noreply.github.com> +Kieran +Kyle Roth +Laurenศ›iu Nicola +Mario A <10923513+Midblyte@users.noreply.github.com> +Matthew Crossman +Matthew E +Mennaruuk <52135169+Mennaruuk@users.noreply.github.com> +mikupls <93015331+mikupls@users.noreply.github.com> +Nainar +Nathan Moos +Nicholas Christopher +Nick Lowery +Nico +obeho <71698631+obeho@users.noreply.github.com> +obscurity +Om G <34579088+OxyMagnesium@users.noreply.github.com> +RiversideRocks <59586759+RiversideRocks@users.noreply.github.com> +robin <8597693+robrobinbin@users.noreply.github.com> +Robin <8597693+robrobinbin@users.noreply.github.com> +robrobinbin <> +robrobinbin <8597693+robrobinbin@users.noreply.github.com> +robrobinbin +Ruben Elshof <15641671+rubenelshof@users.noreply.github.com> +Scoder12 <34356756+Scoder12@users.noreply.github.com> +Slayer <51095261+GhostSlayer@users.noreply.github.com> +Soheb +somini +somoso +Spike <19519553+spikecodes@users.noreply.github.com> +spikecodes <19519553+spikecodes@users.noreply.github.com> +sybenx +TheCultLeader666 <65368815+TheCultLeader666@users.noreply.github.com> +TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com> +The TwilightBlood +tirz <36501933+tirz@users.noreply.github.com> +Tsvetomir Bonev +Vladislav Nepogodin +Walkx +Wichai <1482605+Chengings@users.noreply.github.com> +xatier +Zach <72994911+zachjmurphy@users.noreply.github.com> diff --git a/scripts/gen-credits.sh b/scripts/gen-credits.sh new file mode 100755 index 0000000..33ce9f4 --- /dev/null +++ b/scripts/gen-credits.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# This scripts generates the CREDITS file in the repository root, which +# contains a list of all contributors ot the Libreddit project. +# +# We use git-log to surface the names and emails of all authors and committers, +# and grep will filter any automated commits due to GitHub. + +set -o pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/../" || exit 1 +git --no-pager log --pretty='%an <%ae>%n%cn <%ce>' master \ + | sort -t'<' -u -k1,1 -k2,2 \ + | grep -Fv -- 'GitHub ' \ + > CREDITS From 465d9b7ba715f30d16a74da8c1a79b42d86eefb8 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Mon, 7 Nov 2022 20:54:49 -0700 Subject: [PATCH 38/92] Implement 'posts hidden because of NSFW'. (Resolves #159) (#619) --- src/client.rs | 6 +----- src/search.rs | 6 +++++- src/subreddit.rs | 6 +++++- src/user.rs | 8 ++++++-- templates/search.html | 5 +++++ templates/subreddit.html | 4 ++++ templates/user.html | 4 ++++ 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/client.rs b/src/client.rs index 92b5529..da78304 100644 --- a/src/client.rs +++ b/src/client.rs @@ -46,11 +46,7 @@ pub async fn canonical_path(path: String) -> Result, String> { res .headers() .get(header::LOCATION) - .map(|val| percent_encode(val.as_bytes(), CONTROLS) - .to_string() - .trim_start_matches(REDDIT_URL_BASE) - .to_string() - ), + .map(|val| percent_encode(val.as_bytes(), CONTROLS).to_string().trim_start_matches(REDDIT_URL_BASE).to_string()), ) } diff --git a/src/search.rs b/src/search.rs index 4dd3b5f..4b13594 100644 --- a/src/search.rs +++ b/src/search.rs @@ -42,6 +42,8 @@ struct SearchTemplate { /// Whether all fetched posts are filtered (to differentiate between no posts fetched in the first place, /// and all fetched posts being filtered). all_posts_filtered: bool, + /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) + all_posts_hidden_nsfw: bool, } // SERVICES @@ -100,12 +102,13 @@ pub async fn find(req: Request) -> Result, String> { url, is_filtered: true, all_posts_filtered: false, + all_posts_hidden_nsfw: false, }) } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { let all_posts_filtered = filter_posts(&mut posts, &filters); - + let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(SearchTemplate { posts, subreddits, @@ -123,6 +126,7 @@ pub async fn find(req: Request) -> Result, String> { url, is_filtered: false, all_posts_filtered, + all_posts_hidden_nsfw, }) } Err(msg) => { diff --git a/src/subreddit.rs b/src/subreddit.rs index b03e7e9..75e271a 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -24,6 +24,8 @@ struct SubredditTemplate { /// Whether all fetched posts are filtered (to differentiate between no posts fetched in the first place, /// and all fetched posts being filtered). all_posts_filtered: bool, + /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) + all_posts_hidden_nsfw: bool, } #[derive(Template)] @@ -111,12 +113,13 @@ pub async fn community(req: Request) -> Result, String> { redirect_url, is_filtered: true, all_posts_filtered: false, + all_posts_hidden_nsfw: false, }) } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { let all_posts_filtered = filter_posts(&mut posts, &filters); - + let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(SubredditTemplate { sub, posts, @@ -127,6 +130,7 @@ pub async fn community(req: Request) -> Result, String> { redirect_url, is_filtered: false, all_posts_filtered, + all_posts_hidden_nsfw, }) } Err(msg) => match msg.as_str() { diff --git a/src/user.rs b/src/user.rs index 69c4ae9..0d03f2e 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,7 +1,7 @@ // CRATES use crate::client::json; use crate::server::RequestExt; -use crate::utils::{error, filter_posts, format_url, get_filters, param, template, Post, Preferences, User}; +use crate::utils::{error, filter_posts, format_url, get_filters, param, setting, template, Post, Preferences, User}; use askama::Template; use hyper::{Body, Request, Response}; use time::{macros::format_description, OffsetDateTime}; @@ -24,6 +24,8 @@ struct UserTemplate { /// Whether all fetched posts are filtered (to differentiate between no posts fetched in the first place, /// and all fetched posts being filtered). all_posts_filtered: bool, + /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) + all_posts_hidden_nsfw: bool, } // FUNCTIONS @@ -58,13 +60,14 @@ pub async fn profile(req: Request) -> Result, String> { redirect_url, is_filtered: true, all_posts_filtered: false, + all_posts_hidden_nsfw: false, }) } else { // Request user posts/comments from Reddit match Post::fetch(&path, false).await { Ok((mut posts, after)) => { let all_posts_filtered = filter_posts(&mut posts, &filters); - + let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(UserTemplate { user, posts, @@ -76,6 +79,7 @@ pub async fn profile(req: Request) -> Result, String> { redirect_url, is_filtered: false, all_posts_filtered, + all_posts_hidden_nsfw, }) } // If there is an error show error page diff --git a/templates/search.html b/templates/search.html index 9386f35..b53e279 100644 --- a/templates/search.html +++ b/templates/search.html @@ -56,6 +56,11 @@
{% endif %} {% endif %} + + {% if all_posts_hidden_nsfw %} +
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
+ {% endif %} + {% if all_posts_filtered %}
(All content on this page has been filtered)
{% else if is_filtered %} diff --git a/templates/subreddit.html b/templates/subreddit.html index e5e8fa1..4fdad65 100644 --- a/templates/subreddit.html +++ b/templates/subreddit.html @@ -46,6 +46,10 @@ {% endif %} + {% if all_posts_hidden_nsfw %} +
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
+ {% endif %} + {% if all_posts_filtered %}
(All content on this page has been filtered)
{% else %} diff --git a/templates/user.html b/templates/user.html index 3097dfd..04dc4e6 100644 --- a/templates/user.html +++ b/templates/user.html @@ -32,6 +32,10 @@ + {% if all_posts_hidden_nsfw %} +
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
+ {% endif %} + {% if all_posts_filtered %}
(All content on this page has been filtered)
{% else %} From e62d33ccaed7742b3ed15bc5472fa9422f28d251 Mon Sep 17 00:00:00 2001 From: NKIPSC <15067635+NKIPSC@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:35:23 -0600 Subject: [PATCH 39/92] Blur NSFW posts. Reimplementation of libreddit/libreddit#482. Co-authored by: Daniel Valentine --- app.json | 3 +++ src/client.rs | 6 +---- src/settings.rs | 3 ++- src/utils.rs | 2 ++ static/style.css | 45 ++++++++++++++++++++++++++------ templates/post.html | 38 +++++++++++++++------------ templates/settings.html | 7 ++++- templates/utils.html | 57 ++++++++++++++++++++++++----------------- 8 files changed, 107 insertions(+), 54 deletions(-) diff --git a/app.json b/app.json index 8573671..fd41fc8 100644 --- a/app.json +++ b/app.json @@ -32,6 +32,9 @@ "LIBREDDIT_DEFAULT_SHOW_NSFW": { "required": false }, + "LIBREDDIT_DEFAULT_BLUR_NSFW": { + "required": false + }, "LIBREDDIT_USE_HLS": { "required": false }, diff --git a/src/client.rs b/src/client.rs index 92b5529..da78304 100644 --- a/src/client.rs +++ b/src/client.rs @@ -46,11 +46,7 @@ pub async fn canonical_path(path: String) -> Result, String> { res .headers() .get(header::LOCATION) - .map(|val| percent_encode(val.as_bytes(), CONTROLS) - .to_string() - .trim_start_matches(REDDIT_URL_BASE) - .to_string() - ), + .map(|val| percent_encode(val.as_bytes(), CONTROLS).to_string().trim_start_matches(REDDIT_URL_BASE).to_string()), ) } diff --git a/src/settings.rs b/src/settings.rs index 9cdd266..0fd2640 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -19,7 +19,7 @@ struct SettingsTemplate { // CONSTANTS -const PREFS: [&str; 10] = [ +const PREFS: [&str; 11] = [ "theme", "front_page", "layout", @@ -27,6 +27,7 @@ const PREFS: [&str; 10] = [ "comment_sort", "post_sort", "show_nsfw", + "blur_nsfw", "use_hls", "hide_hls_notification", "autoplay_videos", diff --git a/src/utils.rs b/src/utils.rs index a458cd8..0f15537 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -462,6 +462,7 @@ pub struct Preferences { pub layout: String, pub wide: String, pub show_nsfw: String, + pub blur_nsfw: String, pub hide_hls_notification: String, pub use_hls: String, pub autoplay_videos: String, @@ -493,6 +494,7 @@ impl Preferences { layout: setting(&req, "layout"), wide: setting(&req, "wide"), show_nsfw: setting(&req, "show_nsfw"), + blur_nsfw: setting(&req, "blur_nsfw"), use_hls: setting(&req, "use_hls"), hide_hls_notification: setting(&req, "hide_hls_notification"), autoplay_videos: setting(&req, "autoplay_videos"), diff --git a/static/style.css b/static/style.css index 1552c22..ba07fc2 100644 --- a/static/style.css +++ b/static/style.css @@ -716,22 +716,39 @@ a.search_subreddit:hover { font-weight: bold; } -.post_media_image, .post .__NoScript_PlaceHolder__, .post_media_video, .gallery { +.post_media_content, .post .__NoScript_PlaceHolder__, .gallery { max-width: calc(100% - 40px); grid-area: post_media; margin: 15px auto 5px auto; + width: auto; height: auto; + overflow: hidden; } - -.post_media_video.short { - max-height: 512px; +.post_media_video { width: auto; + height: auto; + max-width: 100%; + max-height: 512px; + display: block; + margin: auto; } .post_media_image.short svg, .post_media_image.short img{ - max-height: 512px; width: auto; + height: auto; + max-width: 100%; + max-height: 512px; + display: block; + margin: auto; +} + +.post_nsfw_blur { + filter: blur(1.5rem); +} + +.post_nsfw_blur:hover { + filter: none; } .post_media_image svg{ @@ -827,13 +844,25 @@ a.search_subreddit:hover { margin: 5px; } -.post_thumbnail svg { +.post_thumbnail div { grid-area: 1 / 1 / 2 / 2; - width: 100%; - height: auto; object-fit: cover; align-self: center; justify-self: center; + overflow: hidden; +} + +.post_thumbnail div svg { + width: 100%; + height: auto; +} + +.post_thumbnail span { + z-index: 0; +} + +.thumb_nsfw_blur { + filter: blur(0.3rem) } .post_thumbnail.no_thumbnail { diff --git a/templates/post.html b/templates/post.html index e447eb3..8f12131 100644 --- a/templates/post.html +++ b/templates/post.html @@ -68,27 +68,33 @@ {% if post.post_type == "image" %} - - - - - Post image - - - +
+ + + + + Post image + + + +
{% else if post.post_type == "video" || post.post_type == "gif" %} {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %} - +
+ +
{% else %} - +
+ +
{% call utils::render_hls_notification(post.permalink[1..]) %} {% endif %} {% else if post.post_type == "gallery" %} diff --git a/templates/settings.html b/templates/settings.html index 60ee109..ed5809d 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -54,6 +54,11 @@ +
+ + + +
@@ -110,7 +115,7 @@

Note: settings and subscriptions are saved in browser cookies. Clearing your cookies will reset them.


-

You can restore your current settings and subscriptions after clearing your cookies using this link.

+

You can restore your current settings and subscriptions after clearing your cookies using this link.

diff --git a/templates/utils.html b/templates/utils.html index 7864200..110dcbe 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -94,27 +94,36 @@ {% if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "image" %} - - - - - Post image - - - +
+ + + + + Post image + + + +
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "gif" %} - +
+ +
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "video" %} {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %} - +
+ +
{% else %} - +
+ +
{% call render_hls_notification(format!("{}%23{}", &self.url[1..].replace("&", "%26").replace("+", "%2B"), post.id)) %} {% endif %} {% else if post.post_type != "self" %} @@ -125,12 +134,14 @@ {% else %} - - - - Thumbnail - - +
+ + + + Thumbnail + + +
{% endif %} {% if post.post_type == "link" %}{{ post.domain }}{% else %}{{ post.post_type }}{% endif %} From d8c661177b7c21129aea9ccbfda78b4ac4e433c1 Mon Sep 17 00:00:00 2001 From: Spike <19519553+spikecodes@users.noreply.github.com> Date: Fri, 11 Nov 2022 09:43:18 -0800 Subject: [PATCH 40/92] Update Google PageInsights speed comparison --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9e23c8f..211ec4c 100644 --- a/README.md +++ b/README.md @@ -69,15 +69,15 @@ This section outlines how Libreddit compares to Reddit. ## Speed -Lasted tested Jan 17, 2021. +Lasted tested Nov 11, 2022. -Results from Google Lighthouse ([Libreddit Report](https://lighthouse-dot-webdotdevsite.appspot.com/lh/html?url=https%3A%2F%2Flibredd.it), [Reddit Report](https://lighthouse-dot-webdotdevsite.appspot.com/lh/html?url=https%3A%2F%2Fwww.reddit.com%2F)). +Results from Google PageSpeed Insights ([Libreddit Report](https://pagespeed.web.dev/report?url=https%3A%2F%2Flibreddit.spike.codes%2F), [Reddit Report](https://pagespeed.web.dev/report?url=https://www.reddit.com)). -| | Libreddit | Reddit | -|------------------------|---------------|------------| -| Requests | 20 | 70 | -| Resource Size (card ui)| 1,224 KiB | 1,690 KiB | -| Time to Interactive | **1.5 s** | **11.2 s** | +| | Libreddit | Reddit | +|------------------------|-------------|-----------| +| Requests | 60 | 83 | +| Speed Index | 2.0s | 10.4s | +| Time to Interactive | **2.8s** | **12.4s** | ## Privacy From 501b47894c3dc3bb912eafa1f54c10c5c7c20480 Mon Sep 17 00:00:00 2001 From: Artemis <51862164+artemislena@users.noreply.github.com> Date: Sat, 12 Nov 2022 19:37:58 +0100 Subject: [PATCH 41/92] Add "BLUR_NSFW" to the list of settings in README (#639) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 211ec4c..f80f5d7 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,7 @@ Assign a default value for each setting by passing environment variables to Libr | `POST_SORT` | `["hot", "new", "top", "rising", "controversial"]` | `hot` | | `COMMENT_SORT` | `["confidence", "top", "new", "controversial", "old"]` | `confidence` | | `SHOW_NSFW` | `["on", "off"]` | `off` | +| `BLUR_NSFW` | `["on", "off"]` | `off` | | `USE_HLS` | `["on", "off"]` | `off` | | `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` | | `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` | From 3f3d9e9c3b073c1da696b3019f95e7008d3b3693 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:08:44 -0800 Subject: [PATCH 42/92] Indicate pinned posts on user profiles (close #606) --- Cargo.lock | 49 +++++++++++++++++++------------------------------ Cargo.toml | 10 +++++----- src/post.rs | 3 ++- src/utils.rs | 2 +- 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd537f6..f64eb3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,9 +211,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" -version = "1.0.74" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" [[package]] name = "cfg-if" @@ -223,9 +223,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.0.18" +version = "4.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" +checksum = "60494cedb60cb47462c0ff7be53de32c0e42a6fc2c772184554fa12bd9489c03" dependencies = [ "bitflags", "clap_lex", @@ -543,9 +543,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.22" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.23.2" +version = "0.24.0" dependencies = [ "askama", "async-recursion", @@ -777,15 +777,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "once_cell" version = "1.16.0" @@ -800,9 +791,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.3.1" +version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" +checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" [[package]] name = "parking" @@ -853,9 +844,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" @@ -916,9 +907,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -927,9 +918,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "ring" @@ -1211,13 +1202,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ "itoa", - "libc", - "num_threads", "serde", "time-core", "time-macros", @@ -1231,9 +1220,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index da1ee8a..b638940 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.23.2" +version = "0.24.0" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" @@ -11,18 +11,18 @@ edition = "2021" askama = { version = "0.11.1", default-features = false } async-recursion = "1.0.0" cached = "0.40.0" -clap = { version = "4.0.18", default-features = false, features = ["std"] } -regex = "1.6.0" +clap = { version = "4.0.24", default-features = false, features = ["std"] } +regex = "1.7.0" serde = { version = "1.0.147", features = ["derive"] } cookie = "0.16.1" futures-lite = "1.12.0" -hyper = { version = "0.14.22", features = ["full"] } +hyper = { version = "0.14.23", features = ["full"] } hyper-rustls = "0.23.0" percent-encoding = "2.2.0" route-recognizer = "0.3.1" serde_json = "1.0.87" tokio = { version = "1.21.2", features = ["full"] } -time = "0.3.16" +time = "0.3.17" url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } libflate = "1.2.0" diff --git a/src/post.rs b/src/post.rs index 5f3142a..d2843c7 100644 --- a/src/post.rs +++ b/src/post.rs @@ -155,7 +155,8 @@ async fn parse_post(json: &serde_json::Value) -> Post { }, flags: Flags { nsfw: post["data"]["over_18"].as_bool().unwrap_or(false), - stickied: post["data"]["stickied"].as_bool().unwrap_or(false), + stickied: post["data"]["stickied"].as_bool().unwrap_or(false) + || post["data"]["pinned"].as_bool().unwrap_or(false), }, domain: val(post, "domain"), rel_time, diff --git a/src/utils.rs b/src/utils.rs index 0f15537..9d58e31 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -319,7 +319,7 @@ impl Post { }, flags: Flags { nsfw: data["over_18"].as_bool().unwrap_or_default(), - stickied: data["stickied"].as_bool().unwrap_or_default(), + stickied: data["stickied"].as_bool().unwrap_or_default() || data["pinned"].as_bool().unwrap_or_default(), }, permalink: val(post, "permalink"), rel_time, From 40dfddc44d93c1f07bef290f69264a633c3d428a Mon Sep 17 00:00:00 2001 From: Lena <102762572+MarshDeer@users.noreply.github.com> Date: Sun, 20 Nov 2022 17:49:20 -0300 Subject: [PATCH 43/92] Added gruvbox-dark and gruvbox-light themes (#490) --- README.md | 2 +- static/themes/gruvboxdark.css | 13 +++++++++++++ static/themes/gruvboxlight.css | 13 +++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 static/themes/gruvboxdark.css create mode 100644 static/themes/gruvboxlight.css diff --git a/README.md b/README.md index f80f5d7..ed7aa30 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Assign a default value for each setting by passing environment variables to Libr | Name | Possible values | Default value | |-------------------------|-----------------------------------------------------------------------------------------------------|---------------| -| `THEME` | `["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold", "rosebox"]` | `system` | +| `THEME` | `["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold", "rosebox", "gruvboxdark", "gruvboxlight"]` | `system` | | `FRONT_PAGE` | `["default", "popular", "all"]` | `default` | | `LAYOUT` | `["card", "clean", "compact"]` | `card` | | `WIDE` | `["on", "off"]` | `off` | diff --git a/static/themes/gruvboxdark.css b/static/themes/gruvboxdark.css new file mode 100644 index 0000000..fb9e3ee --- /dev/null +++ b/static/themes/gruvboxdark.css @@ -0,0 +1,13 @@ +/* Gruvbox-Dark theme setting */ +.gruvboxdark { + --accent: #8ec07c; + --green: #b8bb26; + --text: #ebdbb2; + --foreground: #3c3836; + --background: #282828; + --outside: #3c3836; + --post: #3c3836; + --panel-border: 1px solid #504945; + --highlighted: #282828; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} diff --git a/static/themes/gruvboxlight.css b/static/themes/gruvboxlight.css new file mode 100644 index 0000000..d39f8e9 --- /dev/null +++ b/static/themes/gruvboxlight.css @@ -0,0 +1,13 @@ +/* Gruvbox-Light theme setting */ +.gruvboxlight { + --accent: #427b58; + --green: #79740e; + --text: #3c3836; + --foreground: #ebdbb2; + --background: #fbf1c7; + --outside: #ebdbb2; + --post: #ebdbb2; + --panel-border: 1px solid #d5c4a1; + --highlighted: #fbf1c7; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.25); +} From 3a33c70e7c0b7c284ab4090dded23c3d22c7b2bd Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sun, 20 Nov 2022 17:52:28 -0700 Subject: [PATCH 44/92] Update CREDITS file. --- CREDITS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CREDITS b/CREDITS index 2bfb498..0e681df 100644 --- a/CREDITS +++ b/CREDITS @@ -37,6 +37,7 @@ Kieran <42723993+EnderDev@users.noreply.github.com> Kieran Kyle Roth Laurenศ›iu Nicola +Lena <102762572+MarshDeer@users.noreply.github.com> Mario A <10923513+Midblyte@users.noreply.github.com> Matthew Crossman Matthew E @@ -47,6 +48,7 @@ Nathan Moos Nicholas Christopher Nick Lowery Nico +NKIPSC <15067635+NKIPSC@users.noreply.github.com> obeho <71698631+obeho@users.noreply.github.com> obscurity Om G <34579088+OxyMagnesium@users.noreply.github.com> From 88bed73e5e881e3a1e76cfb3efa5468595441903 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Mon, 21 Nov 2022 08:58:40 -0700 Subject: [PATCH 45/92] Extract Location URL path correctly in client::request. (fixes #645) (#646) --- src/client.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/client.rs b/src/client.rs index da78304..f577f95 100644 --- a/src/client.rs +++ b/src/client.rs @@ -158,10 +158,21 @@ fn request(method: &'static Method, path: String, redirect: bool, quarantine: bo method, response .headers() - .get("Location") + .get(header::LOCATION) .map(|val| { - let new_url = percent_encode(val.as_bytes(), CONTROLS).to_string(); - format!("{}{}raw_json=1", new_url, if new_url.contains('?') { "&" } else { "?" }) + // We need to make adjustments to the URI + // we get back from Reddit. Namely, we + // must: + // + // 1. Remove the authority (e.g. + // https://www.reddit.com) that may be + // present, so that we recurse on the + // path (and query parameters) as + // required. + // + // 2. Percent-encode the path. + let new_path = percent_encode(val.as_bytes(), CONTROLS).to_string().trim_start_matches(REDDIT_URL_BASE).to_string(); + format!("{}{}raw_json=1", new_path, if new_path.contains('?') { "&" } else { "?" }) }) .unwrap_or_default() .to_string(), From f0fa2f270937154e8a3d895ae406517fd190b6ef Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 00:16:55 -0700 Subject: [PATCH 46/92] Dockerfile.arm: disable cargo build parallelization --- Dockerfile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index 93703d0..0596d14 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -9,7 +9,7 @@ WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --path . +RUN cargo install --jobs=1 --path=. #################################################################################################### ## Final image From f76243e0af45bcd193475bbe392ba65cae5400d3 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 00:22:15 -0700 Subject: [PATCH 47/92] Revert "Dockerfile.arm: disable cargo build parallelization" This reverts commit f0fa2f270937154e8a3d895ae406517fd190b6ef. This did not stop the OS from issuing SIGKILL to cargo and/or one of its child processes. --- Dockerfile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index 0596d14..93703d0 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -9,7 +9,7 @@ WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --jobs=1 --path=. +RUN cargo install --path . #################################################################################################### ## Final image From 6912307349e9172297adbbbc22554de379b79c58 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 12:14:12 -0700 Subject: [PATCH 48/92] Update version to v0.24.1. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f64eb3d..dff606e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.24.0" +version = "0.24.1" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index b638940..6350f2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.24.0" +version = "0.24.1" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 01527529137d0f5258cbd3e8d15ee3d9d5e6a764 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 15:29:02 -0700 Subject: [PATCH 49/92] Dockerfile.arm: Verbose cargo install. Temporarily provide `--verbose` to `cargo install` to track when during the build the process(es) receive SIGKILL. --- Dockerfile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index 93703d0..b051423 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -9,7 +9,7 @@ WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --path . +RUN cargo install --verbose --path . #################################################################################################### ## Final image From c9633e14648366d87dbe069d17fe2a24301351a3 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 15:32:45 -0700 Subject: [PATCH 50/92] Revert "Dockerfile.arm: Verbose cargo install." This reverts commit 01527529137d0f5258cbd3e8d15ee3d9d5e6a764. --- Dockerfile.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index b051423..93703d0 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -9,7 +9,7 @@ WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --verbose --path . +RUN cargo install --path . #################################################################################################### ## Final image From 5aee695baef4d46a200f829b08396e7cfa185e5b Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 15:38:17 -0700 Subject: [PATCH 51/92] Dockerfile.arm: Force cargo to use git binary. Hopefully resolves #641. --- Dockerfile.arm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index 93703d0..0319d77 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -9,7 +9,11 @@ WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --path . +# net.git-fetch-with-cli is specified in order to prevent a potential OOM kill +# in low memory environments. See: +# https://users.rust-lang.org/t/cargo-uses-too-much-memory-being-run-in-qemu/76531 +# This is tracked under issue #641. +RUN cargo install --config net.git-fetch-with-cli=true --path . #################################################################################################### ## Final image From ab39b625332151a92fd8ce9804ed9f2fca09de2d Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 22 Nov 2022 15:42:10 -0700 Subject: [PATCH 52/92] Dockerfile.arm: Add git to builder. --- Dockerfile.arm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile.arm b/Dockerfile.arm index 0319d77..098bf13 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -3,7 +3,7 @@ #################################################################################################### FROM rust:alpine AS builder -RUN apk add --no-cache g++ +RUN apk add --no-cache g++ git WORKDIR /usr/src/libreddit @@ -12,7 +12,8 @@ COPY . . # net.git-fetch-with-cli is specified in order to prevent a potential OOM kill # in low memory environments. See: # https://users.rust-lang.org/t/cargo-uses-too-much-memory-being-run-in-qemu/76531 -# This is tracked under issue #641. +# This is tracked under issue #641. This also requires us to install git in the +# builder. RUN cargo install --config net.git-fetch-with-cli=true --path . #################################################################################################### From d86cebf9752e5166a5d03e75bc3d72032b80ca83 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Wed, 23 Nov 2022 14:43:36 -0700 Subject: [PATCH 53/92] Request CSS with explicit version. base.html will now request with a query parameter `v=` whose value is the current version of Libreddit. This will cause the browser to request the stylesheet for a specific version of Libreddit, bypassing the cache. A new version of Libreddit will cause the browser to fetch a new stylesheet. Resolves #622. Credit is due to GitHub user @chloekek for offering this solution in the following post: https://github.com/libreddit/libreddit/issues/622#issuecomment-1315961742 --- templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/base.html b/templates/base.html index f30aaaf..e9b51ec 100644 --- a/templates/base.html +++ b/templates/base.html @@ -19,7 +19,7 @@ - + {% endblock %} - - - - + + {% if post.post_type == "image" %} + + + + {% else if post.post_type == "video" || post.post_type == "gif" %} + + + + + {% else %} + + {% endif %} {% endblock %} {% block subscriptions %} From 0a6bf6bbee84266098e9e744d48946ba1724957b Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sun, 27 Nov 2022 15:57:31 -0700 Subject: [PATCH 55/92] Update CREDITS file. --- CREDITS | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS b/CREDITS index 0e681df..dd81af5 100644 --- a/CREDITS +++ b/CREDITS @@ -38,6 +38,7 @@ Kieran Kyle Roth Laurenศ›iu Nicola Lena <102762572+MarshDeer@users.noreply.github.com> +Macic <46872282+Macic-Dev@users.noreply.github.com> Mario A <10923513+Midblyte@users.noreply.github.com> Matthew Crossman Matthew E From 92f528666711fc7b0b63118928ad4962299dd117 Mon Sep 17 00:00:00 2001 From: laazyCmd Date: Wed, 30 Nov 2022 21:06:21 -0700 Subject: [PATCH 56/92] Make the column size in posts consistent. Signed-off-by: Daniel Valentine --- Cargo.lock | 2 +- Cargo.toml | 2 +- static/style.css | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dff606e..5658dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.24.1" +version = "0.24.2" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 6350f2d..381570c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.24.1" +version = "0.24.2" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" diff --git a/static/style.css b/static/style.css index ba07fc2..df15723 100644 --- a/static/style.css +++ b/static/style.css @@ -154,6 +154,7 @@ main { } #column_one { + width: 100%; max-width: 750px; border-radius: 5px; overflow: inherit; From 473a498beab3d466778014f78f7710e6b0d87275 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Wed, 30 Nov 2022 21:08:51 -0700 Subject: [PATCH 57/92] Update CREDITS file. --- CREDITS | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS b/CREDITS index dd81af5..2def374 100644 --- a/CREDITS +++ b/CREDITS @@ -36,6 +36,7 @@ Kazi Kieran <42723993+EnderDev@users.noreply.github.com> Kieran Kyle Roth +laazyCmd Laurenศ›iu Nicola Lena <102762572+MarshDeer@users.noreply.github.com> Macic <46872282+Macic-Dev@users.noreply.github.com> From 8fa8a449cf1b4909c38bbc06d41b297f78cfe9cc Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 1 Dec 2022 16:42:04 -0700 Subject: [PATCH 58/92] Sign release (resolves #651). --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5658dc5..cdfffb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.24.2" +version = "0.24.3" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 381570c..4a55d4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.24.2" +version = "0.24.3" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From e579b97442b569c0d18bcd4ff6239f249cc07e8b Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Wed, 9 Nov 2022 09:16:51 -0700 Subject: [PATCH 59/92] List post duplicates (resolves #574). --- CREDITS | 4 + Cargo.lock | 49 +++---- Cargo.toml | 10 +- Dockerfile.arm | 9 +- README.md | 17 +-- src/client.rs | 17 ++- src/duplicates.rs | 228 +++++++++++++++++++++++++++++++++ src/main.rs | 6 + src/post.rs | 90 +------------ src/search.rs | 2 +- src/subreddit.rs | 2 +- src/user.rs | 2 +- src/utils.rs | 113 ++++++++++++++-- static/style.css | 39 ++++++ static/themes/gruvboxdark.css | 13 ++ static/themes/gruvboxlight.css | 13 ++ templates/base.html | 2 +- templates/duplicates.html | 107 ++++++++++++++++ templates/post.html | 113 ++-------------- templates/search.html | 6 +- templates/utils.html | 103 +++++++++++++++ 21 files changed, 695 insertions(+), 250 deletions(-) create mode 100644 src/duplicates.rs create mode 100644 static/themes/gruvboxdark.css create mode 100644 static/themes/gruvboxlight.css create mode 100644 templates/duplicates.html diff --git a/CREDITS b/CREDITS index 2bfb498..2def374 100644 --- a/CREDITS +++ b/CREDITS @@ -36,7 +36,10 @@ Kazi Kieran <42723993+EnderDev@users.noreply.github.com> Kieran Kyle Roth +laazyCmd Laurenศ›iu Nicola +Lena <102762572+MarshDeer@users.noreply.github.com> +Macic <46872282+Macic-Dev@users.noreply.github.com> Mario A <10923513+Midblyte@users.noreply.github.com> Matthew Crossman Matthew E @@ -47,6 +50,7 @@ Nathan Moos Nicholas Christopher Nick Lowery Nico +NKIPSC <15067635+NKIPSC@users.noreply.github.com> obeho <71698631+obeho@users.noreply.github.com> obscurity Om G <34579088+OxyMagnesium@users.noreply.github.com> diff --git a/Cargo.lock b/Cargo.lock index fd537f6..cdfffb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,9 +211,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" -version = "1.0.74" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" [[package]] name = "cfg-if" @@ -223,9 +223,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.0.18" +version = "4.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" +checksum = "60494cedb60cb47462c0ff7be53de32c0e42a6fc2c772184554fa12bd9489c03" dependencies = [ "bitflags", "clap_lex", @@ -543,9 +543,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.22" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.23.2" +version = "0.24.3" dependencies = [ "askama", "async-recursion", @@ -777,15 +777,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "once_cell" version = "1.16.0" @@ -800,9 +791,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.3.1" +version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" +checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" [[package]] name = "parking" @@ -853,9 +844,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" @@ -916,9 +907,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -927,9 +918,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "ring" @@ -1211,13 +1202,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ "itoa", - "libc", - "num_threads", "serde", "time-core", "time-macros", @@ -1231,9 +1220,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index da1ee8a..4a55d4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.23.2" +version = "0.24.3" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" @@ -11,18 +11,18 @@ edition = "2021" askama = { version = "0.11.1", default-features = false } async-recursion = "1.0.0" cached = "0.40.0" -clap = { version = "4.0.18", default-features = false, features = ["std"] } -regex = "1.6.0" +clap = { version = "4.0.24", default-features = false, features = ["std"] } +regex = "1.7.0" serde = { version = "1.0.147", features = ["derive"] } cookie = "0.16.1" futures-lite = "1.12.0" -hyper = { version = "0.14.22", features = ["full"] } +hyper = { version = "0.14.23", features = ["full"] } hyper-rustls = "0.23.0" percent-encoding = "2.2.0" route-recognizer = "0.3.1" serde_json = "1.0.87" tokio = { version = "1.21.2", features = ["full"] } -time = "0.3.16" +time = "0.3.17" url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } libflate = "1.2.0" diff --git a/Dockerfile.arm b/Dockerfile.arm index 93703d0..098bf13 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -3,13 +3,18 @@ #################################################################################################### FROM rust:alpine AS builder -RUN apk add --no-cache g++ +RUN apk add --no-cache g++ git WORKDIR /usr/src/libreddit COPY . . -RUN cargo install --path . +# net.git-fetch-with-cli is specified in order to prevent a potential OOM kill +# in low memory environments. See: +# https://users.rust-lang.org/t/cargo-uses-too-much-memory-being-run-in-qemu/76531 +# This is tracked under issue #641. This also requires us to install git in the +# builder. +RUN cargo install --config net.git-fetch-with-cli=true --path . #################################################################################################### ## Final image diff --git a/README.md b/README.md index 9e23c8f..ed7aa30 100644 --- a/README.md +++ b/README.md @@ -69,15 +69,15 @@ This section outlines how Libreddit compares to Reddit. ## Speed -Lasted tested Jan 17, 2021. +Lasted tested Nov 11, 2022. -Results from Google Lighthouse ([Libreddit Report](https://lighthouse-dot-webdotdevsite.appspot.com/lh/html?url=https%3A%2F%2Flibredd.it), [Reddit Report](https://lighthouse-dot-webdotdevsite.appspot.com/lh/html?url=https%3A%2F%2Fwww.reddit.com%2F)). +Results from Google PageSpeed Insights ([Libreddit Report](https://pagespeed.web.dev/report?url=https%3A%2F%2Flibreddit.spike.codes%2F), [Reddit Report](https://pagespeed.web.dev/report?url=https://www.reddit.com)). -| | Libreddit | Reddit | -|------------------------|---------------|------------| -| Requests | 20 | 70 | -| Resource Size (card ui)| 1,224 KiB | 1,690 KiB | -| Time to Interactive | **1.5 s** | **11.2 s** | +| | Libreddit | Reddit | +|------------------------|-------------|-----------| +| Requests | 60 | 83 | +| Speed Index | 2.0s | 10.4s | +| Time to Interactive | **2.8s** | **12.4s** | ## Privacy @@ -188,13 +188,14 @@ Assign a default value for each setting by passing environment variables to Libr | Name | Possible values | Default value | |-------------------------|-----------------------------------------------------------------------------------------------------|---------------| -| `THEME` | `["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold", "rosebox"]` | `system` | +| `THEME` | `["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold", "rosebox", "gruvboxdark", "gruvboxlight"]` | `system` | | `FRONT_PAGE` | `["default", "popular", "all"]` | `default` | | `LAYOUT` | `["card", "clean", "compact"]` | `card` | | `WIDE` | `["on", "off"]` | `off` | | `POST_SORT` | `["hot", "new", "top", "rising", "controversial"]` | `hot` | | `COMMENT_SORT` | `["confidence", "top", "new", "controversial", "old"]` | `confidence` | | `SHOW_NSFW` | `["on", "off"]` | `off` | +| `BLUR_NSFW` | `["on", "off"]` | `off` | | `USE_HLS` | `["on", "off"]` | `off` | | `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` | | `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` | diff --git a/src/client.rs b/src/client.rs index da78304..f577f95 100644 --- a/src/client.rs +++ b/src/client.rs @@ -158,10 +158,21 @@ fn request(method: &'static Method, path: String, redirect: bool, quarantine: bo method, response .headers() - .get("Location") + .get(header::LOCATION) .map(|val| { - let new_url = percent_encode(val.as_bytes(), CONTROLS).to_string(); - format!("{}{}raw_json=1", new_url, if new_url.contains('?') { "&" } else { "?" }) + // We need to make adjustments to the URI + // we get back from Reddit. Namely, we + // must: + // + // 1. Remove the authority (e.g. + // https://www.reddit.com) that may be + // present, so that we recurse on the + // path (and query parameters) as + // required. + // + // 2. Percent-encode the path. + let new_path = percent_encode(val.as_bytes(), CONTROLS).to_string().trim_start_matches(REDDIT_URL_BASE).to_string(); + format!("{}{}raw_json=1", new_path, if new_path.contains('?') { "&" } else { "?" }) }) .unwrap_or_default() .to_string(), diff --git a/src/duplicates.rs b/src/duplicates.rs new file mode 100644 index 0000000..6a64fc8 --- /dev/null +++ b/src/duplicates.rs @@ -0,0 +1,228 @@ +// Handler for post duplicates. + +use crate::client::json; +use crate::server::RequestExt; +use crate::subreddit::{can_access_quarantine, quarantine}; +use crate::utils::{error, filter_posts, get_filters, parse_post, template, Post, Preferences}; + +use askama::Template; +use hyper::{Body, Request, Response}; +use serde_json::Value; +use std::borrow::ToOwned; +use std::collections::HashSet; +use std::vec::Vec; + +/// DuplicatesParams contains the parameters in the URL. +struct DuplicatesParams { + before: String, + after: String, + sort: String, +} + +/// DuplicatesTemplate defines an Askama template for rendering duplicate +/// posts. +#[derive(Template)] +#[template(path = "duplicates.html")] +struct DuplicatesTemplate { + /// params contains the relevant request parameters. + params: DuplicatesParams, + + /// post is the post whose ID is specified in the reqeust URL. Note that + /// this is not necessarily the "original" post. + post: Post, + + /// duplicates is the list of posts that, per Reddit, are duplicates of + /// Post above. + duplicates: Vec, + + /// prefs are the user preferences. + prefs: Preferences, + + /// url is the request URL. + url: String, + + /// num_posts_filtered counts how many posts were filtered from the + /// duplicates list. + num_posts_filtered: u64, + + /// all_posts_filtered is true if every duplicate was filtered. This is an + /// edge case but can still happen. + all_posts_filtered: bool, +} + +/// Make the GET request to Reddit. It assumes `req` is the appropriate Reddit +/// REST endpoint for enumerating post duplicates. +pub async fn item(req: Request) -> Result, String> { + let path: String = format!("{}.json?{}&raw_json=1", req.uri().path(), req.uri().query().unwrap_or_default()); + let sub = req.param("sub").unwrap_or_default(); + let quarantined = can_access_quarantine(&req, &sub); + + // Log the request in debugging mode + #[cfg(debug_assertions)] + dbg!(req.param("id").unwrap_or_default()); + + // Send the GET, and await JSON. + match json(path, quarantined).await { + // Process response JSON. + Ok(response) => { + let filters = get_filters(&req); + let post = parse_post(&response[0]["data"]["children"][0]).await; + let (duplicates, num_posts_filtered, all_posts_filtered) = parse_duplicates(&response[1], &filters).await; + + // These are the values for the "before=", "after=", and "sort=" + // query params, respectively. + let mut before: String = String::new(); + let mut after: String = String::new(); + let mut sort: String = String::new(); + + // FIXME: We have to perform a kludge to work around a Reddit API + // bug. + // + // The JSON object in "data" will never contain a "before" value so + // it is impossible to use it to determine our position in a + // listing. We'll make do by getting the ID of the first post in + // the listing, setting that as our "before" value, and ask Reddit + // to give us a batch of duplicate posts up to that post. + // + // Likewise, if we provide a "before" request in the GET, the + // result won't have an "after" in the JSON, in addition to missing + // the "before." So we will have to use the final post in the list + // of duplicates. + // + // That being said, we'll also need to capture the value of the + // "sort=" parameter as well, so we will need to inspect the + // query key-value pairs anyway. + let l = duplicates.len(); + if l > 0 { + // This gets set to true if "before=" is one of the GET params. + let mut have_before: bool = false; + + // This gets set to true if "after=" is one of the GET params. + let mut have_after: bool = false; + + // Inspect the query key-value pairs. We will need to record + // the value of "sort=", along with checking to see if either + // one of "before=" or "after=" are given. + // + // If we're in the middle of the batch (evidenced by the + // presence of a "before=" or "after=" parameter in the GET), + // then use the first post as the "before" reference. + // + // We'll do this iteratively. Better than with .map_or() + // since a closure will continue to operate on remaining + // elements even after we've determined one of "before=" or + // "after=" (or both) are in the GET request. + // + // In practice, here should only ever be one of "before=" or + // "after=" and never both. + let query_str = req.uri().query().unwrap_or_default().to_string(); + + if !query_str.is_empty() { + for param in query_str.split('&') { + let kv: Vec<&str> = param.split('=').collect(); + if kv.len() < 2 { + // Reject invalid query parameter. + continue; + } + + let key: &str = kv[0]; + match key { + "before" => have_before = true, + "after" => have_after = true, + "sort" => { + let val: &str = kv[1]; + match val { + "new" | "num_comments" => sort = val.to_string(), + _ => {} + } + } + _ => {} + } + } + } + + if have_after { + before = "t3_".to_owned(); + before.push_str(&duplicates[0].id); + } + + // Address potentially missing "after". If "before=" is in the + // GET, then "after" will be null in the JSON (see FIXME + // above). + if have_before { + // The next batch will need to start from one after the + // last post in the current batch. + after = "t3_".to_owned(); + after.push_str(&duplicates[l - 1].id); + + // Here is where things get terrible. Notice that we + // haven't set `before`. In order to do so, we will + // need to know if there is a batch that exists before + // this one, and doing so requires actually fetching the + // previous batch. In other words, we have to do yet one + // more GET to Reddit. There is no other way to determine + // whether or not to define `before`. + // + // We'll mitigate that by requesting at most one duplicate. + let new_path: String = format!( + "{}.json?before=t3_{}&sort={}&limit=1&raw_json=1", + req.uri().path(), + &duplicates[0].id, + if sort.is_empty() { "num_comments".to_string() } else { sort.clone() } + ); + match json(new_path, true).await { + Ok(response) => { + if !response[1]["data"]["children"].as_array().unwrap_or(&Vec::new()).is_empty() { + before = "t3_".to_owned(); + before.push_str(&duplicates[0].id); + } + } + Err(msg) => { + // Abort entirely if we couldn't get the previous + // batch. + return error(req, msg).await; + } + } + } else { + after = response[1]["data"]["after"].as_str().unwrap_or_default().to_string(); + } + } + let url = req.uri().to_string(); + + template(DuplicatesTemplate { + params: DuplicatesParams { before, after, sort }, + post, + duplicates, + prefs: Preferences::new(req), + url, + num_posts_filtered, + all_posts_filtered, + }) + } + + // Process error. + Err(msg) => { + if msg == "quarantined" { + let sub = req.param("sub").unwrap_or_default(); + quarantine(req, sub) + } else { + error(req, msg).await + } + } + } +} + +// DUPLICATES +async fn parse_duplicates(json: &serde_json::Value, filters: &HashSet) -> (Vec, u64, bool) { + let post_duplicates: &Vec = &json["data"]["children"].as_array().map_or(Vec::new(), ToOwned::to_owned); + let mut duplicates: Vec = Vec::new(); + + // Process each post and place them in the Vec. + for val in post_duplicates.iter() { + let post: Post = parse_post(val).await; + duplicates.push(post); + } + + let (num_posts_filtered, all_posts_filtered) = filter_posts(&mut duplicates, filters); + (duplicates, num_posts_filtered, all_posts_filtered) +} diff --git a/src/main.rs b/src/main.rs index 8592e3c..3b45bd2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ #![allow(clippy::cmp_owned)] // Reference local files +mod duplicates; mod post; mod search; mod settings; @@ -244,6 +245,11 @@ async fn main() { app.at("/comments/:id/:title").get(|r| post::item(r).boxed()); app.at("/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed()); + app.at("/r/:sub/duplicates/:id").get(|r| duplicates::item(r).boxed()); + app.at("/r/:sub/duplicates/:id/:title").get(|r| duplicates::item(r).boxed()); + app.at("/duplicates/:id").get(|r| duplicates::item(r).boxed()); + app.at("/duplicates/:id/:title").get(|r| duplicates::item(r).boxed()); + app.at("/r/:sub/search").get(|r| search::find(r).boxed()); app diff --git a/src/post.rs b/src/post.rs index 5f3142a..e467fe7 100644 --- a/src/post.rs +++ b/src/post.rs @@ -3,7 +3,7 @@ use crate::client::json; use crate::server::RequestExt; use crate::subreddit::{can_access_quarantine, quarantine}; use crate::utils::{ - error, format_num, format_url, get_filters, param, rewrite_urls, setting, template, time, val, Author, Awards, Comment, Flags, Flair, FlairPart, Media, Post, Preferences, + error, format_num, get_filters, param, parse_post, rewrite_urls, setting, template, time, val, Author, Awards, Comment, Flair, FlairPart, Post, Preferences, }; use hyper::{Body, Request, Response}; @@ -54,7 +54,7 @@ pub async fn item(req: Request) -> Result, String> { // Otherwise, grab the JSON output from the request Ok(response) => { // Parse the JSON into Post and Comment structs - let post = parse_post(&response[0]).await; + let post = parse_post(&response[0]["data"]["children"][0]).await; let comments = parse_comments(&response[1], &post.permalink, &post.author.name, highlighted_comment, &get_filters(&req)); let url = req.uri().to_string(); @@ -80,92 +80,6 @@ pub async fn item(req: Request) -> Result, String> { } } -// POSTS -async fn parse_post(json: &serde_json::Value) -> Post { - // Retrieve post (as opposed to comments) from JSON - let post: &serde_json::Value = &json["data"]["children"][0]; - - // Grab UTC time as unix timestamp - let (rel_time, created) = time(post["data"]["created_utc"].as_f64().unwrap_or_default()); - // Parse post score and upvote ratio - let score = post["data"]["score"].as_i64().unwrap_or_default(); - let ratio: f64 = post["data"]["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0; - - // Determine the type of media along with the media URL - let (post_type, media, gallery) = Media::parse(&post["data"]).await; - - let awards: Awards = Awards::parse(&post["data"]["all_awardings"]); - - let permalink = val(post, "permalink"); - - let body = if val(post, "removed_by_category") == "moderator" { - format!( - "

[removed] โ€” view removed post

", - permalink - ) - } else { - rewrite_urls(&val(post, "selftext_html")) - }; - - // Build a post using data parsed from Reddit post API - Post { - id: val(post, "id"), - title: val(post, "title"), - community: val(post, "subreddit"), - body, - author: Author { - name: val(post, "author"), - flair: Flair { - flair_parts: FlairPart::parse( - post["data"]["author_flair_type"].as_str().unwrap_or_default(), - post["data"]["author_flair_richtext"].as_array(), - post["data"]["author_flair_text"].as_str(), - ), - text: val(post, "link_flair_text"), - background_color: val(post, "author_flair_background_color"), - foreground_color: val(post, "author_flair_text_color"), - }, - distinguished: val(post, "distinguished"), - }, - permalink, - score: format_num(score), - upvote_ratio: ratio as i64, - post_type, - media, - thumbnail: Media { - url: format_url(val(post, "thumbnail").as_str()), - alt_url: String::new(), - width: post["data"]["thumbnail_width"].as_i64().unwrap_or_default(), - height: post["data"]["thumbnail_height"].as_i64().unwrap_or_default(), - poster: "".to_string(), - }, - flair: Flair { - flair_parts: FlairPart::parse( - post["data"]["link_flair_type"].as_str().unwrap_or_default(), - post["data"]["link_flair_richtext"].as_array(), - post["data"]["link_flair_text"].as_str(), - ), - text: val(post, "link_flair_text"), - background_color: val(post, "link_flair_background_color"), - foreground_color: if val(post, "link_flair_text_color") == "dark" { - "black".to_string() - } else { - "white".to_string() - }, - }, - flags: Flags { - nsfw: post["data"]["over_18"].as_bool().unwrap_or(false), - stickied: post["data"]["stickied"].as_bool().unwrap_or(false), - }, - domain: val(post, "domain"), - rel_time, - created, - comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), - gallery, - awards, - } -} - // COMMENTS fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, highlighted_comment: &str, filters: &HashSet) -> Vec { // Parse the comment JSON into a Vector of Comments diff --git a/src/search.rs b/src/search.rs index 4b13594..0a62b06 100644 --- a/src/search.rs +++ b/src/search.rs @@ -107,7 +107,7 @@ pub async fn find(req: Request) -> Result, String> { } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { - let all_posts_filtered = filter_posts(&mut posts, &filters); + let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(SearchTemplate { posts, diff --git a/src/subreddit.rs b/src/subreddit.rs index 75e271a..4aff027 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -118,7 +118,7 @@ pub async fn community(req: Request) -> Result, String> { } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { - let all_posts_filtered = filter_posts(&mut posts, &filters); + let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(SubredditTemplate { sub, diff --git a/src/user.rs b/src/user.rs index 0d03f2e..8c0540c 100644 --- a/src/user.rs +++ b/src/user.rs @@ -66,7 +66,7 @@ pub async fn profile(req: Request) -> Result, String> { // Request user posts/comments from Reddit match Post::fetch(&path, false).await { Ok((mut posts, after)) => { - let all_posts_filtered = filter_posts(&mut posts, &filters); + let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; template(UserTemplate { user, diff --git a/src/utils.rs b/src/utils.rs index 0f15537..06237e9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -225,6 +225,7 @@ pub struct Post { pub domain: String, pub rel_time: String, pub created: String, + pub num_duplicates: u64, pub comments: (String, String), pub gallery: Vec, pub awards: Awards, @@ -319,11 +320,12 @@ impl Post { }, flags: Flags { nsfw: data["over_18"].as_bool().unwrap_or_default(), - stickied: data["stickied"].as_bool().unwrap_or_default(), + stickied: data["stickied"].as_bool().unwrap_or_default() || data["pinned"].as_bool().unwrap_or_default(), }, permalink: val(post, "permalink"), rel_time, created, + num_duplicates: post["data"]["num_duplicates"].as_u64().unwrap_or(0), comments: format_num(data["num_comments"].as_i64().unwrap_or_default()), gallery, awards, @@ -511,15 +513,110 @@ pub fn get_filters(req: &Request) -> HashSet { setting(req, "filters").split('+').map(String::from).filter(|s| !s.is_empty()).collect::>() } -/// Filters a `Vec` by the given `HashSet` of filters (each filter being a subreddit name or a user name). If a -/// `Post`'s subreddit or author is found in the filters, it is removed. Returns `true` if _all_ posts were filtered -/// out, or `false` otherwise. -pub fn filter_posts(posts: &mut Vec, filters: &HashSet) -> bool { +/// Filters a `Vec` by the given `HashSet` of filters (each filter being +/// a subreddit name or a user name). If a `Post`'s subreddit or author is +/// found in the filters, it is removed. +/// +/// The first value of the return tuple is the number of posts filtered. The +/// second return value is `true` if all posts were filtered. +pub fn filter_posts(posts: &mut Vec, filters: &HashSet) -> (u64, bool) { + // This is the length of the Vec prior to applying the filter. + let lb: u64 = posts.len().try_into().unwrap_or(0); + if posts.is_empty() { - false + (0, false) } else { - posts.retain(|p| !filters.contains(&p.community) && !filters.contains(&["u_", &p.author.name].concat())); - posts.is_empty() + posts.retain(|p| !(filters.contains(&p.community) || filters.contains(&["u_", &p.author.name].concat()))); + + // Get the length of the Vec after applying the filter. + // If lb > la, then at least one post was removed. + let la: u64 = posts.len().try_into().unwrap_or(0); + + (lb - la, posts.is_empty()) + } +} + +/// Creates a [`Post`] from a provided JSON. +pub async fn parse_post(post: &serde_json::Value) -> Post { + // Grab UTC time as unix timestamp + let (rel_time, created) = time(post["data"]["created_utc"].as_f64().unwrap_or_default()); + // Parse post score and upvote ratio + let score = post["data"]["score"].as_i64().unwrap_or_default(); + let ratio: f64 = post["data"]["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0; + + // Determine the type of media along with the media URL + let (post_type, media, gallery) = Media::parse(&post["data"]).await; + + let awards: Awards = Awards::parse(&post["data"]["all_awardings"]); + + let permalink = val(post, "permalink"); + + let body = if val(post, "removed_by_category") == "moderator" { + format!( + "

[removed] โ€” view removed post

", + permalink + ) + } else { + rewrite_urls(&val(post, "selftext_html")) + }; + + // Build a post using data parsed from Reddit post API + Post { + id: val(post, "id"), + title: val(post, "title"), + community: val(post, "subreddit"), + body, + author: Author { + name: val(post, "author"), + flair: Flair { + flair_parts: FlairPart::parse( + post["data"]["author_flair_type"].as_str().unwrap_or_default(), + post["data"]["author_flair_richtext"].as_array(), + post["data"]["author_flair_text"].as_str(), + ), + text: val(post, "link_flair_text"), + background_color: val(post, "author_flair_background_color"), + foreground_color: val(post, "author_flair_text_color"), + }, + distinguished: val(post, "distinguished"), + }, + permalink, + score: format_num(score), + upvote_ratio: ratio as i64, + post_type, + media, + thumbnail: Media { + url: format_url(val(post, "thumbnail").as_str()), + alt_url: String::new(), + width: post["data"]["thumbnail_width"].as_i64().unwrap_or_default(), + height: post["data"]["thumbnail_height"].as_i64().unwrap_or_default(), + poster: String::new(), + }, + flair: Flair { + flair_parts: FlairPart::parse( + post["data"]["link_flair_type"].as_str().unwrap_or_default(), + post["data"]["link_flair_richtext"].as_array(), + post["data"]["link_flair_text"].as_str(), + ), + text: val(post, "link_flair_text"), + background_color: val(post, "link_flair_background_color"), + foreground_color: if val(post, "link_flair_text_color") == "dark" { + "black".to_string() + } else { + "white".to_string() + }, + }, + flags: Flags { + nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(), + stickied: post["data"]["stickied"].as_bool().unwrap_or_default() || post["data"]["pinned"].as_bool().unwrap_or(false), + }, + domain: val(post, "domain"), + rel_time, + created, + num_duplicates: post["data"]["num_duplicates"].as_u64().unwrap_or(0), + comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), + gallery, + awards, } } diff --git a/static/style.css b/static/style.css index ba07fc2..500646d 100644 --- a/static/style.css +++ b/static/style.css @@ -154,6 +154,7 @@ main { } #column_one { + width: 100%; max-width: 750px; border-radius: 5px; overflow: inherit; @@ -834,6 +835,16 @@ a.search_subreddit:hover { margin-right: 15px; } +#post_links > li.desktop_item { + display: auto; +} + +@media screen and (min-width: 480px) { + #post_links > li.mobile_item { + display: none; + } +} + .post_thumbnail { border-radius: 5px; border: var(--panel-border); @@ -1272,6 +1283,29 @@ td, th { #error h3 { opacity: 0.85; } #error a { color: var(--accent); } +/* Messages */ + +#duplicates_msg h3 { + display: inline-block; + margin-top: 10px; + margin-bottom: 10px; + text-align: center; + width: 100%; +} + +/* Warnings */ + +.listing_warn { + display: inline-block; + margin: 10px; + text-align: center; + width: 100%; +} + +.listing_warn a { + color: var(--accent); +} + /* Mobile */ @media screen and (max-width: 800px) { @@ -1372,4 +1406,9 @@ td, th { padding: 7px 0px; margin-right: -5px; } + + #post_links > li { margin-right: 10px } + #post_links > li.desktop_item { display: none } + #post_links > li.mobile_item { display: auto } + .post_footer > p > span#upvoted { display: none } } diff --git a/static/themes/gruvboxdark.css b/static/themes/gruvboxdark.css new file mode 100644 index 0000000..fb9e3ee --- /dev/null +++ b/static/themes/gruvboxdark.css @@ -0,0 +1,13 @@ +/* Gruvbox-Dark theme setting */ +.gruvboxdark { + --accent: #8ec07c; + --green: #b8bb26; + --text: #ebdbb2; + --foreground: #3c3836; + --background: #282828; + --outside: #3c3836; + --post: #3c3836; + --panel-border: 1px solid #504945; + --highlighted: #282828; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} diff --git a/static/themes/gruvboxlight.css b/static/themes/gruvboxlight.css new file mode 100644 index 0000000..d39f8e9 --- /dev/null +++ b/static/themes/gruvboxlight.css @@ -0,0 +1,13 @@ +/* Gruvbox-Light theme setting */ +.gruvboxlight { + --accent: #427b58; + --green: #79740e; + --text: #3c3836; + --foreground: #ebdbb2; + --background: #fbf1c7; + --outside: #ebdbb2; + --post: #ebdbb2; + --panel-border: 1px solid #d5c4a1; + --highlighted: #fbf1c7; + --shadow: 0 1px 3px rgba(0, 0, 0, 0.25); +} diff --git a/templates/base.html b/templates/base.html index f30aaaf..e9b51ec 100644 --- a/templates/base.html +++ b/templates/base.html @@ -19,7 +19,7 @@ - + {% endblock %} + {% call utils::post(post) %} + + + {% if post.num_duplicates == 0 %} + (No duplicates found) + {% else if post.flags.nsfw && prefs.show_nsfw != "on" %} + (Enable "Show NSFW posts" in settings to show duplicates) + {% else %} +

Duplicates

+ {% if num_posts_filtered > 0 %} + + {% if all_posts_filtered %} + (All posts have been filtered) + {% else %} + (Some posts have been filtered) + {% endif %} + + {% endif %} + + + +
+ {% for post in duplicates -%} + {# TODO: utils::post should be reworked to permit a truncated display of a post as below #} + {% if !(post.flags.nsfw) || prefs.show_nsfw == "on" %} +
+

+ {% let community -%} + {% if post.community.starts_with("u_") -%} + {% let community = format!("u/{}", &post.community[2..]) -%} + {% else -%} + {% let community = format!("r/{}", post.community) -%} + {% endif -%} + {{ post.community }} + + + + {{ post.rel_time }} + {% if !post.awards.is_empty() %} + {% for award in post.awards.clone() %} + + {{ award.name }} + + {% endfor %} + {% endif %} +

+

+ {% if post.flair.flair_parts.len() > 0 %} + {% call utils::render_flair(post.flair.flair_parts) %} + {% endif %} + {{ post.title }}{% if post.flags.nsfw %} NSFW{% endif %} +

+ +
{{ post.score.0 }} Upvotes
+ + +
+ {% endif %} + {%- endfor %} +
+ +
+ {% if params.before != "" %} + PREV + {% endif %} + + {% if params.after != "" %} + NEXT + {% endif %} +
+ {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/templates/post.html b/templates/post.html index 8f12131..d69644b 100644 --- a/templates/post.html +++ b/templates/post.html @@ -13,16 +13,25 @@ - - - - + + {% if post.post_type == "image" %} + + + + {% else if post.post_type == "video" || post.post_type == "gif" %} + + + + + {% else %} + + {% endif %} {% endblock %} {% block subscriptions %} @@ -31,101 +40,7 @@ {% block content %}
- - -
-

- r/{{ post.community }} - - - {% if post.author.flair.flair_parts.len() > 0 %} - {% call utils::render_flair(post.author.flair.flair_parts) %} - {% endif %} - - {{ post.rel_time }} - {% if !post.awards.is_empty() %} - - - {% for award in post.awards.clone() %} - - {{ award.name }} - {{ award.count }} - - {% endfor %} - - {% endif %} -

-

- {{ post.title }} - {% if post.flair.flair_parts.len() > 0 %} - {% call utils::render_flair(post.flair.flair_parts) %} - {% endif %} - {% if post.flags.nsfw %} NSFW{% endif %} -

- - - - {% if post.post_type == "image" %} -
- - - - - Post image - - - -
- {% else if post.post_type == "video" || post.post_type == "gif" %} - {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %} - -
- -
- - {% else %} -
- -
- {% call utils::render_hls_notification(post.permalink[1..]) %} - {% endif %} - {% else if post.post_type == "gallery" %} - - {% else if post.post_type == "link" %} - {{ post.media.url }} - {% endif %} - - -
{{ post.body|safe }}
-
{{ post.score.0 }} Upvotes
- -
+ {% call utils::post(post) %}
diff --git a/templates/search.html b/templates/search.html index b53e279..43fadb4 100644 --- a/templates/search.html +++ b/templates/search.html @@ -58,13 +58,13 @@ {% endif %} {% if all_posts_hidden_nsfw %} -
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
+ All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view. {% endif %} {% if all_posts_filtered %} -
(All content on this page has been filtered)
+ (All content on this page has been filtered) {% else if is_filtered %} -
(Content from r/{{ sub }} has been filtered)
+ (Content from r/{{ sub }} has been filtered) {% else if params.typed != "sr_user" %} {% for post in posts %} {% if post.flags.nsfw && prefs.show_nsfw != "on" %} diff --git a/templates/utils.html b/templates/utils.html index 110dcbe..87d47a3 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -61,6 +61,109 @@ {% endif %} {%- endmacro %} +{% macro post(post) -%} + +
+

+ r/{{ post.community }} + + + {% if post.author.flair.flair_parts.len() > 0 %} + {% call render_flair(post.author.flair.flair_parts) %} + {% endif %} + + {{ post.rel_time }} + {% if !post.awards.is_empty() %} + + + {% for award in post.awards.clone() %} + + {{ award.name }} + {{ award.count }} + + {% endfor %} + + {% endif %} +

+

+ {{ post.title }} + {% if post.flair.flair_parts.len() > 0 %} + {% call render_flair(post.flair.flair_parts) %} + {% endif %} + {% if post.flags.nsfw %} NSFW{% endif %} +

+ + + + {% if post.post_type == "image" %} +
+ + + + + Post image + + + +
+ {% else if post.post_type == "video" || post.post_type == "gif" %} + {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %} + +
+ +
+ + {% else %} +
+ +
+ {% call render_hls_notification(post.permalink[1..]) %} + {% endif %} + {% else if post.post_type == "gallery" %} + + {% else if post.post_type == "link" %} + {{ post.media.url }} + {% endif %} + + +
{{ post.body|safe }}
+
{{ post.score.0 }} Upvotes
+ +
+{%- endmacro %} + {% macro post_in_list(post) -%}

From 7391a5bc7a647d9c350761778eb3e49b53701d13 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 3 Dec 2022 01:18:23 -0700 Subject: [PATCH 60/92] v0.25.0 --- CREDITS | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 2def374..0d7d117 100644 --- a/CREDITS +++ b/CREDITS @@ -16,6 +16,7 @@ BobIsMyManager curlpipe <11898833+curlpipe@users.noreply.github.com> dacousb <53299044+dacousb@users.noreply.github.com> Daniel Valentine +Daniel Valentine dbrennand <52419383+dbrennand@users.noreply.github.com> Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com> Dyras diff --git a/Cargo.lock b/Cargo.lock index cdfffb3..87c1b9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.24.3" +version = "0.25.0" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 4a55d4c..5136235 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.24.3" +version = "0.25.0" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 225380b7d9d3dbb09222270cd8ced4da4ff6c60d Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Sun, 4 Dec 2022 10:57:19 -0800 Subject: [PATCH 61/92] Fix workflow to push to new Libreddit Docker repo --- .github/workflows/docker-arm.yml | 2 +- .github/workflows/docker-armv7.yml | 2 +- .github/workflows/docker.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-arm.yml b/.github/workflows/docker-arm.yml index 6e34e79..251e325 100644 --- a/.github/workflows/docker-arm.yml +++ b/.github/workflows/docker-arm.yml @@ -33,6 +33,6 @@ jobs: file: ./Dockerfile.arm platforms: linux/arm64 push: true - tags: spikecodes/libreddit:arm + tags: libreddit/libreddit:arm cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/docker-armv7.yml b/.github/workflows/docker-armv7.yml index 7c51db2..d2817d8 100644 --- a/.github/workflows/docker-armv7.yml +++ b/.github/workflows/docker-armv7.yml @@ -36,6 +36,6 @@ jobs: file: ./Dockerfile.armv7 platforms: linux/arm/v7 push: true - tags: spikecodes/libreddit:armv7 + tags: libreddit/libreddit:armv7 cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ed1bf73..d9c9c5b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -33,6 +33,6 @@ jobs: file: ./Dockerfile platforms: linux/amd64 push: true - tags: spikecodes/libreddit:latest + tags: libreddit/libreddit:latest cache-from: type=gha cache-to: type=gha,mode=max From dc06ae3b29a18ddb0d0e13b0654afa8543a5365f Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Sun, 4 Dec 2022 11:01:28 -0800 Subject: [PATCH 62/92] Automatically-update Docker Repo description --- .github/workflows/docker.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d9c9c5b..0f25fae 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -26,6 +26,12 @@ jobs: with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} + - name: Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + repository: libreddit/libreddit - name: Build and push uses: docker/build-push-action@v2 with: From 87729d0daafb25b545c70157e037d3a3dd027bee Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Sun, 4 Dec 2022 11:05:19 -0800 Subject: [PATCH 63/92] Use new libreddit org for GitLab and Docker links --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ed7aa30..891e6c9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Both files are part of the [libreddit-instances](https://github.com/libreddit/li # About -Find Libreddit on ๐Ÿ’ฌ [Matrix](https://matrix.to/#/#libreddit:kde.org), ๐Ÿ‹ [Docker](https://hub.docker.com/r/spikecodes/libreddit), :octocat: [GitHub](https://github.com/libreddit/libreddit), and ๐ŸฆŠ [GitLab](https://gitlab.com/spikecodes/libreddit). +Find Libreddit on ๐Ÿ’ฌ [Matrix](https://matrix.to/#/#libreddit:kde.org), ๐Ÿ‹ [Docker](https://hub.docker.com/r/libreddit/libreddit), :octocat: [GitHub](https://github.com/libreddit/libreddit), and ๐ŸฆŠ [GitLab](https://gitlab.com/libreddit/libreddit). ## Built with @@ -136,21 +136,21 @@ cargo install libreddit ## 2) Docker -Deploy the [Docker image](https://hub.docker.com/r/spikecodes/libreddit) of Libreddit: +Deploy the [Docker image](https://hub.docker.com/r/libreddit/libreddit) of Libreddit: ``` -docker pull spikecodes/libreddit -docker run -d --name libreddit -p 8080:8080 spikecodes/libreddit +docker pull libreddit/libreddit +docker run -d --name libreddit -p 8080:8080 libreddit/libreddit ``` Deploy using a different port (in this case, port 80): ``` -docker pull spikecodes/libreddit -docker run -d --name libreddit -p 80:8080 spikecodes/libreddit +docker pull libreddit/libreddit +docker run -d --name libreddit -p 80:8080 libreddit/libreddit ``` -To deploy on `arm64` platforms, simply replace `spikecodes/libreddit` in the commands above with `spikecodes/libreddit:arm`. +To deploy on `arm64` platforms, simply replace `libreddit/libreddit` in the commands above with `libreddit/libreddit:arm`. -To deploy on `armv7` platforms, simply replace `spikecodes/libreddit` in the commands above with `spikecodes/libreddit:armv7`. +To deploy on `armv7` platforms, simply replace `libreddit/libreddit` in the commands above with `libreddit/libreddit:armv7`. ## 3) AUR From 7e752b3d819ea0cd2b10be55832d75f52f2539c8 Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Sun, 4 Dec 2022 11:07:18 -0800 Subject: [PATCH 64/92] Fix Docker credential secrets --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0f25fae..c90bd4d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -29,8 +29,8 @@ jobs: - name: Docker Hub Description uses: peter-evans/dockerhub-description@v3 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} repository: libreddit/libreddit - name: Build and push uses: docker/build-push-action@v2 From 5d518cfc1890b64e8b76bfbae931c99a5def5fa5 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 3 Dec 2022 19:11:31 -0700 Subject: [PATCH 65/92] Cache result of `server::determine_compressor`. --- src/server.rs | 74 +++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/src/server.rs b/src/server.rs index c277b6b..501b933 100644 --- a/src/server.rs +++ b/src/server.rs @@ -243,7 +243,7 @@ impl Server { match func.await { Ok(mut res) => { res.headers_mut().extend(def_headers); - let _ = compress_response(req_headers, &mut res).await; + let _ = compress_response(&req_headers, &mut res).await; Ok(res) } @@ -282,7 +282,7 @@ async fn new_boilerplate( ) -> Result, String> { match Response::builder().status(status).body(body) { Ok(mut res) => { - let _ = compress_response(req_headers, &mut res).await; + let _ = compress_response(&req_headers, &mut res).await; res.headers_mut().extend(default_headers.clone()); Ok(res) @@ -306,7 +306,8 @@ async fn new_boilerplate( /// Accept-Encoding: gzip, compress, br /// Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1 /// ``` -fn determine_compressor(accept_encoding: &str) -> Option { +#[cached] +fn determine_compressor(accept_encoding: String) -> Option { if accept_encoding.is_empty() { return None; }; @@ -473,7 +474,7 @@ fn determine_compressor(accept_encoding: &str) -> Option { /// /// This function logs errors to stderr, but only in debug mode. No information /// is logged in release builds. -async fn compress_response(req_headers: HeaderMap, res: &mut Response) -> Result<(), String> { +async fn compress_response(req_headers: &HeaderMap, res: &mut Response) -> Result<(), String> { // Check if the data is eligible for compression. if let Some(hdr) = res.headers().get(header::CONTENT_TYPE) { match from_utf8(hdr.as_bytes()) { @@ -503,30 +504,22 @@ async fn compress_response(req_headers: HeaderMap, res: &mu return Ok(()); }; - // Quick and dirty closure for extracting a header from the request and - // returning it as a &str. - let get_req_header = |k: header::HeaderName| -> Option<&str> { - match req_headers.get(k) { - Some(hdr) => match from_utf8(hdr.as_bytes()) { - Ok(val) => Some(val), - - #[cfg(debug_assertions)] - Err(e) => { - dbg_msg!(e); - None - } - - #[cfg(not(debug_assertions))] - Err(_) => None, - }, - None => None, - } - }; - // Check to see which compressor is requested, and if we can use it. - let accept_encoding: &str = match get_req_header(header::ACCEPT_ENCODING) { - Some(val) => val, + let accept_encoding: String = match req_headers.get(header::ACCEPT_ENCODING) { None => return Ok(()), // Client requested no compression. + + Some(hdr) => match String::from_utf8(hdr.as_bytes().into()) { + Ok(val) => val, + + #[cfg(debug_assertions)] + Err(e) => { + dbg_msg!(e); + return Ok(()); + } + + #[cfg(not(debug_assertions))] + Err(_) => return Ok(()), + }, }; let compressor: CompressionType = match determine_compressor(accept_encoding) { @@ -636,18 +629,18 @@ mod tests { #[test] fn test_determine_compressor() { // Single compressor given. - assert_eq!(determine_compressor("unsupported"), None); - assert_eq!(determine_compressor("gzip"), Some(CompressionType::Gzip)); - assert_eq!(determine_compressor("*"), Some(DEFAULT_COMPRESSOR)); + assert_eq!(determine_compressor("unsupported".to_string()), None); + assert_eq!(determine_compressor("gzip".to_string()), Some(CompressionType::Gzip)); + assert_eq!(determine_compressor("*".to_string()), Some(DEFAULT_COMPRESSOR)); // Multiple compressors. - assert_eq!(determine_compressor("gzip, br"), Some(CompressionType::Brotli)); - assert_eq!(determine_compressor("gzip;q=0.8, br;q=0.3"), Some(CompressionType::Gzip)); - assert_eq!(determine_compressor("br, gzip"), Some(CompressionType::Brotli)); - assert_eq!(determine_compressor("br;q=0.3, gzip;q=0.4"), Some(CompressionType::Gzip)); + assert_eq!(determine_compressor("gzip, br".to_string()), Some(CompressionType::Brotli)); + assert_eq!(determine_compressor("gzip;q=0.8, br;q=0.3".to_string()), Some(CompressionType::Gzip)); + assert_eq!(determine_compressor("br, gzip".to_string()), Some(CompressionType::Brotli)); + assert_eq!(determine_compressor("br;q=0.3, gzip;q=0.4".to_string()), Some(CompressionType::Gzip)); // Invalid q-values. - assert_eq!(determine_compressor("gzip;q=NAN"), None); + assert_eq!(determine_compressor("gzip;q=NAN".to_string()), None); } #[test] @@ -672,9 +665,9 @@ mod tests { ] { // Determine what the expected encoding should be based on both the // specific encodings we accept. - let expected_encoding: CompressionType = match determine_compressor(accept_encoding) { + let expected_encoding: CompressionType = match determine_compressor(accept_encoding.to_string()) { Some(s) => s, - None => panic!("determine_compressor(accept_encoding) => None"), + None => panic!("determine_compressor(accept_encoding.to_string()) => None"), }; // Build headers with our Accept-Encoding. @@ -691,8 +684,8 @@ mod tests { .unwrap(); // Perform the compression. - if let Err(e) = block_on(compress_response(req_headers, &mut res)) { - panic!("compress_response(req_headers, &mut res) => Err(\"{}\")", e); + if let Err(e) = block_on(compress_response(&req_headers, &mut res)) { + panic!("compress_response(&req_headers, &mut res) => Err(\"{}\")", e); }; // If the content was compressed, we expect the Content-Encoding @@ -739,9 +732,8 @@ mod tests { }; let mut decompressed = Vec::::new(); - match io::copy(&mut decoder, &mut decompressed) { - Ok(_) => {} - Err(e) => panic!("{}", e), + if let Err(e) = io::copy(&mut decoder, &mut decompressed) { + panic!("{}", e); }; assert!(decompressed.eq(&expected_lorem_ipsum)); From 37d1939dc02ecc641636a9ca36e24f15163fd620 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 13 Dec 2022 21:15:28 -0700 Subject: [PATCH 66/92] Fix #658. Dimensions for embedded video in post are explicitly set only when defined by Reddit. c/o: NKIPSC <15067635+NKIPSC@users.noreply.github.com> --- Cargo.lock | 2 +- Cargo.toml | 2 +- templates/utils.html | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87c1b9a..2865f62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.25.0" +version = "0.25.1" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 5136235..157ed31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.25.0" +version = "0.25.1" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" diff --git a/templates/utils.html b/templates/utils.html index 87d47a3..639b0d8 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -115,7 +115,7 @@ {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}

-
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "gif" %}
- +
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "video" %} {% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}
-
{% else %}
- +
{% call render_hls_notification(format!("{}%23{}", &self.url[1..].replace("&", "%26").replace("+", "%2B"), post.id)) %} {% endif %} From 1fa9f276194fc638234967a4ddf53b68b03b9e74 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 26 Dec 2022 22:57:04 +0100 Subject: [PATCH 67/92] Theme browser scrollbar Hint current color-scheme to the browser. This enables chromium-based browsers to change the scrollbar color according to the current theme. --- static/style.css | 6 ++++++ static/themes/gruvboxlight.css | 5 +++++ static/themes/light.css | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/static/style.css b/static/style.css index 500646d..2b065a9 100644 --- a/static/style.css +++ b/static/style.css @@ -26,6 +26,9 @@ --highlighted: #333; --visited: #aaa; --shadow: 0 1px 3px rgba(0, 0, 0, 0.5); + + /* Hint color theme to browser for scrollbar */ + color-scheme: dark; } /* Browser-defined light theme */ @@ -42,6 +45,9 @@ --highlighted: white; --visited: #555; --shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + + /* Hint color theme to browser for scrollbar */ + color-scheme: light; } } diff --git a/static/themes/gruvboxlight.css b/static/themes/gruvboxlight.css index d39f8e9..49389a5 100644 --- a/static/themes/gruvboxlight.css +++ b/static/themes/gruvboxlight.css @@ -11,3 +11,8 @@ --highlighted: #fbf1c7; --shadow: 0 1px 3px rgba(0, 0, 0, 0.25); } + +html:has(> .gruvboxlight) { + /* Hint color theme to browser for scrollbar */ + color-scheme: light; +} diff --git a/static/themes/light.css b/static/themes/light.css index 1fe0387..ad73b2d 100644 --- a/static/themes/light.css +++ b/static/themes/light.css @@ -11,4 +11,9 @@ --highlighted: white; --visited: #555; --shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +html:has(> .light) { + /* Hint color theme to browser for scrollbar */ + color-scheme: light; } \ No newline at end of file From ab30b8bbecc187284afd05a36b3fa39e37936795 Mon Sep 17 00:00:00 2001 From: gmnsii <95436780+gmnsii@users.noreply.github.com> Date: Sat, 31 Dec 2022 18:11:59 -0800 Subject: [PATCH 68/92] Bugfix: 'all posts are hidden because NSFW' when no posts where found (#666) * Fix 'all_posts_hidden_nsfw' when there are no posts. If a search query yielded no results and the user set nsfw posts to be hidden, libreddit would show 'All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view'. This is fixed by verifying tnat posts.len > 0 before setting 'all_posts_hidden_nsfw' to true. * Add a message when no posts were found. * Delete 2 --- src/search.rs | 6 +++++- src/subreddit.rs | 6 +++++- src/user.rs | 6 +++++- templates/search.html | 4 ++++ templates/subreddit.html | 4 ++++ templates/user.html | 4 ++++ 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/search.rs b/src/search.rs index 0a62b06..9fbe77a 100644 --- a/src/search.rs +++ b/src/search.rs @@ -44,6 +44,7 @@ struct SearchTemplate { all_posts_filtered: bool, /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) all_posts_hidden_nsfw: bool, + no_posts: bool, } // SERVICES @@ -103,12 +104,14 @@ pub async fn find(req: Request) -> Result, String> { is_filtered: true, all_posts_filtered: false, all_posts_hidden_nsfw: false, + no_posts: false, }) } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); - let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; + let no_posts = posts.is_empty(); + let all_posts_hidden_nsfw = !no_posts && (posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"); template(SearchTemplate { posts, subreddits, @@ -127,6 +130,7 @@ pub async fn find(req: Request) -> Result, String> { is_filtered: false, all_posts_filtered, all_posts_hidden_nsfw, + no_posts, }) } Err(msg) => { diff --git a/src/subreddit.rs b/src/subreddit.rs index 4aff027..ef511c2 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -26,6 +26,7 @@ struct SubredditTemplate { all_posts_filtered: bool, /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) all_posts_hidden_nsfw: bool, + no_posts: bool, } #[derive(Template)] @@ -114,12 +115,14 @@ pub async fn community(req: Request) -> Result, String> { is_filtered: true, all_posts_filtered: false, all_posts_hidden_nsfw: false, + no_posts: false, }) } else { match Post::fetch(&path, quarantined).await { Ok((mut posts, after)) => { let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); - let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; + let no_posts = posts.is_empty(); + let all_posts_hidden_nsfw = !no_posts && (posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"); template(SubredditTemplate { sub, posts, @@ -131,6 +134,7 @@ pub async fn community(req: Request) -> Result, String> { is_filtered: false, all_posts_filtered, all_posts_hidden_nsfw, + no_posts, }) } Err(msg) => match msg.as_str() { diff --git a/src/user.rs b/src/user.rs index 8c0540c..6c991ef 100644 --- a/src/user.rs +++ b/src/user.rs @@ -26,6 +26,7 @@ struct UserTemplate { all_posts_filtered: bool, /// Whether all posts were hidden because they are NSFW (and user has disabled show NSFW) all_posts_hidden_nsfw: bool, + no_posts: bool, } // FUNCTIONS @@ -61,13 +62,15 @@ pub async fn profile(req: Request) -> Result, String> { is_filtered: true, all_posts_filtered: false, all_posts_hidden_nsfw: false, + no_posts: false, }) } else { // Request user posts/comments from Reddit match Post::fetch(&path, false).await { Ok((mut posts, after)) => { let (_, all_posts_filtered) = filter_posts(&mut posts, &filters); - let all_posts_hidden_nsfw = posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"; + let no_posts = posts.is_empty(); + let all_posts_hidden_nsfw = !no_posts && (posts.iter().all(|p| p.flags.nsfw) && setting(&req, "show_nsfw") != "on"); template(UserTemplate { user, posts, @@ -80,6 +83,7 @@ pub async fn profile(req: Request) -> Result, String> { is_filtered: false, all_posts_filtered, all_posts_hidden_nsfw, + no_posts, }) } // If there is an error show error page diff --git a/templates/search.html b/templates/search.html index 43fadb4..b9742f6 100644 --- a/templates/search.html +++ b/templates/search.html @@ -61,6 +61,10 @@ All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view. {% endif %} + {% if no_posts %} +
No posts were found.
+ {% endif %} + {% if all_posts_filtered %} (All content on this page has been filtered) {% else if is_filtered %} diff --git a/templates/subreddit.html b/templates/subreddit.html index 4fdad65..9ad1932 100644 --- a/templates/subreddit.html +++ b/templates/subreddit.html @@ -50,6 +50,10 @@
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
{% endif %} + {% if no_posts %} +
No posts were found.
+ {% endif %} + {% if all_posts_filtered %}
(All content on this page has been filtered)
{% else %} diff --git a/templates/user.html b/templates/user.html index 04dc4e6..a72cce0 100644 --- a/templates/user.html +++ b/templates/user.html @@ -36,6 +36,10 @@
All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.
{% endif %} + {% if no_posts %} +
No posts were found.
+ {% endif %} + {% if all_posts_filtered %}
(All content on this page has been filtered)
{% else %} From 9e434e7db6deccd2c6db7bb63a906453e9f963a6 Mon Sep 17 00:00:00 2001 From: gmnsii <95436780+gmnsii@users.noreply.github.com> Date: Sat, 31 Dec 2022 19:57:42 -0800 Subject: [PATCH 69/92] Search - add support for raw reddit links (#663) * Search - add support for raw reddit links If a search query starts with 'https://www.reddit.com/' or 'https://old.reddit.com/', this prefix will be truncated and the query will be processed normally. For example, a search query 'https://www.reddit.com/r/rust' will redirect to r/rust. * Search - support a wider variety of reddit links. Add once cell dependency for static regex support (avoid compiling the same regex multiple times). All search queries are now matched against a regex (provided by @Daniel-Valentine) that determines if it is a reddit link. If it is, the prefix specifying the reddit instance will be truncated from the query that will then be processed normally. For example, the query 'https://www.reddit.com/r/rust' will be treated the same way as the query 'r/rust'. --- Cargo.lock | 1 + Cargo.toml | 1 + src/search.rs | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 2865f62..6945ebe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -677,6 +677,7 @@ dependencies = [ "hyper-rustls", "libflate", "lipsum", + "once_cell", "percent-encoding", "regex", "route-recognizer", diff --git a/Cargo.toml b/Cargo.toml index 157ed31..c1b2548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } libflate = "1.2.0" brotli = { version = "3.3.4", features = ["std"] } +once_cell = "1.16.0" [dev-dependencies] lipsum = "0.8.2" diff --git a/src/search.rs b/src/search.rs index 9fbe77a..87965c3 100644 --- a/src/search.rs +++ b/src/search.rs @@ -7,6 +7,8 @@ use crate::{ }; use askama::Template; use hyper::{Body, Request, Response}; +use once_cell::sync::Lazy; +use regex::Regex; // STRUCTS struct SearchParams { @@ -47,11 +49,15 @@ struct SearchTemplate { no_posts: bool, } +// Regex matched against search queries to determine if they are reddit urls. +static REDDIT_URL_MATCH: Lazy = Lazy::new(|| Regex::new(r"^https?://([^\./]+\.)*reddit.com/").unwrap()); + // SERVICES pub async fn find(req: Request) -> Result, String> { let nsfw_results = if setting(&req, "show_nsfw") == "on" { "&include_over_18=on" } else { "" }; let path = format!("{}.json?{}{}&raw_json=1", req.uri().path(), req.uri().query().unwrap_or_default(), nsfw_results); - let query = param(&path, "q").unwrap_or_default(); + let mut query = param(&path, "q").unwrap_or_default(); + query = REDDIT_URL_MATCH.replace(&query, "").to_string(); if query.is_empty() { return Ok(redirect("/".to_string())); From b5d04f1a50681cc78fc387d04e2f4c59f363d7a0 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sat, 31 Dec 2022 21:34:15 -0700 Subject: [PATCH 70/92] v0.25.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6945ebe..f52164a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.25.1" +version = "0.25.2" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index c1b2548..e67f5e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.25.1" +version = "0.25.2" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 9178b50b73c91289bf296005c429a0597baeb7c6 Mon Sep 17 00:00:00 2001 From: Rupert Angermeier Date: Sun, 1 Jan 2023 09:56:09 +0100 Subject: [PATCH 71/92] fix a11y and HTML issues on settings page (#662) - connect labels with corresponding form controls - use fieldsets to group form sections - don't nest details/summary element into label --- static/style.css | 39 +++++++----- templates/settings.html | 133 +++++++++++++++++++++------------------- 2 files changed, 93 insertions(+), 79 deletions(-) diff --git a/static/style.css b/static/style.css index 500646d..a0d4b69 100644 --- a/static/style.css +++ b/static/style.css @@ -1118,22 +1118,16 @@ summary.comment_data { } .prefs { - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 20px; + padding: 10px 20px 20px; background: var(--post); border-radius: 5px; margin-bottom: 20px; } -.prefs > div { - display: flex; - justify-content: space-between; - width: 100%; - height: 35px; - align-items: center; - margin-top: 7px; +.prefs fieldset { + border: 0; + padding: 10px 0; + margin: 0 0 5px; } .prefs legend { @@ -1141,11 +1135,25 @@ summary.comment_data { border-bottom: 1px solid var(--highlighted); font-size: 18px; padding-bottom: 10px; + margin-bottom: 7px; + width: 100%; + float: left; /* places the legend inside the (invisible) border, instead of vertically centered on top border*/ } -.prefs legend:not(:first-child) { - padding-top: 10px; - margin-top: 15px; +.prefs-group { + display: flex; + width: 100%; + height: 35px; + align-items: center; + margin-top: 7px; +} + +.prefs-group > *:not(:last-child) { + margin-right: 1ch; +} + +.prefs-group > *:last-child { + margin-left: auto; } .prefs select { @@ -1163,7 +1171,8 @@ aside.prefs { background: var(--highlighted); padding: 10px 15px; border-radius: 5px; - margin-top: 20px; + margin-top: 5px; + width: 100% } input[type="submit"] { diff --git a/templates/settings.html b/templates/settings.html index ed5809d..b4bab8c 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -11,74 +11,79 @@
- Appearance -
- - -
- Interface -
- - -
-
- - -
-
- - - -
- Content -
- - -
-
- - -
-
- - - -
-
- - - -
-
- - - -
-
-
+
+ + + +
+
From a49d399f72d334adb5307eda2d23fbfa14d258be Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Sun, 1 Jan 2023 13:38:52 -0500 Subject: [PATCH 72/92] Link to `libreddit/libreddit` and open in new tab This sets the target of the "code" link to `_blank`, so that it will open in a new tab in browsers. Because the GitHub page is a different context from libreddit, and accessing the repository doesn't imply that the user is finished browsing libreddit, this seemed reasonable. This also changes the link from `spikecodes/libreddit` to `libreddit/libreddit`. --- templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/base.html b/templates/base.html index e9b51ec..bbea3bf 100644 --- a/templates/base.html +++ b/templates/base.html @@ -48,7 +48,7 @@ - + code code From b1182e7cf5d4809c1c9636f66a9b3ca8a3424160 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Sun, 1 Jan 2023 14:52:33 -0500 Subject: [PATCH 73/92] Create devcontainer.json --- .devcontainer/devcontainer.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..1c0405f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +{ + "name": "Rust", + "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + }, + "portsAttributes": { + "8080": { + "label": "libreddit", + "onAutoForward": "notify" + } + }, + "postCreateCommand": "cargo build" +} From 9c938c62103d4fd6b7289b97a598f59a24dc32a4 Mon Sep 17 00:00:00 2001 From: tirz <36501933+tirz@users.noreply.github.com> Date: Sun, 1 Jan 2023 22:33:31 +0100 Subject: [PATCH 74/92] build: enable LTO, set codegen-unit to 1 and strip the binary (#467) Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e67f5e1..cc7f517 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,8 @@ once_cell = "1.16.0" [dev-dependencies] lipsum = "0.8.2" + +[profile.release] +codegen-units = 1 +lto = true +strip = true \ No newline at end of file From 6cf374864263132912ea8fcf7a864619d1382cd2 Mon Sep 17 00:00:00 2001 From: elliot <75391956+ellieeet123@users.noreply.github.com> Date: Sun, 1 Jan 2023 17:06:58 -0600 Subject: [PATCH 75/92] Fix for #675 /:id route now accepts 7 character post IDs. --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3b45bd2..25c2aea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -289,7 +289,7 @@ async fn main() { Some("best" | "hot" | "new" | "top" | "rising" | "controversial") => subreddit::community(req).await, // Short link for post - Some(id) if (5..7).contains(&id.len()) => match canonical_path(format!("/{}", id)).await { + Some(id) if (5..8).contains(&id.len()) => match canonical_path(format!("/{}", id)).await { Ok(path_opt) => match path_opt { Some(path) => Ok(redirect(path)), None => error(req, "Post ID is invalid. It may point to a post on a community that has been banned.").await, From 6a785baa2cbec355a1c4a5a6dd35e17b1fc2c39c Mon Sep 17 00:00:00 2001 From: Matthew Esposito Date: Sun, 1 Jan 2023 21:39:38 -0500 Subject: [PATCH 76/92] Add hide_awards config --- src/duplicates.rs | 2 +- src/post.rs | 9 +++++---- src/search.rs | 4 ++-- src/settings.rs | 5 +++-- src/subreddit.rs | 12 ++++++------ src/user.rs | 4 ++-- src/utils.rs | 7 +++++-- templates/comment.html | 2 +- templates/duplicates.html | 4 ++-- templates/settings.html | 5 +++++ templates/utils.html | 4 ++-- 11 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/duplicates.rs b/src/duplicates.rs index 6a64fc8..98e37b2 100644 --- a/src/duplicates.rs +++ b/src/duplicates.rs @@ -193,7 +193,7 @@ pub async fn item(req: Request) -> Result, String> { params: DuplicatesParams { before, after, sort }, post, duplicates, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, num_posts_filtered, all_posts_filtered, diff --git a/src/post.rs b/src/post.rs index e467fe7..79b7648 100644 --- a/src/post.rs +++ b/src/post.rs @@ -55,7 +55,7 @@ pub async fn item(req: Request) -> Result, String> { Ok(response) => { // Parse the JSON into Post and Comment structs let post = parse_post(&response[0]["data"]["children"][0]).await; - let comments = parse_comments(&response[1], &post.permalink, &post.author.name, highlighted_comment, &get_filters(&req)); + let comments = parse_comments(&response[1], &post.permalink, &post.author.name, highlighted_comment, &get_filters(&req), &req); let url = req.uri().to_string(); // Use the Post and Comment structs to generate a website to show users @@ -63,7 +63,7 @@ pub async fn item(req: Request) -> Result, String> { comments, post, sort, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), single_thread, url, }) @@ -81,7 +81,7 @@ pub async fn item(req: Request) -> Result, String> { } // COMMENTS -fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, highlighted_comment: &str, filters: &HashSet) -> Vec { +fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, highlighted_comment: &str, filters: &HashSet, req: &Request) -> Vec { // Parse the comment JSON into a Vector of Comments let comments = json["data"]["children"].as_array().map_or(Vec::new(), std::borrow::ToOwned::to_owned); @@ -101,7 +101,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, // If this comment contains replies, handle those too let replies: Vec = if data["replies"].is_object() { - parse_comments(&data["replies"], post_link, post_author, highlighted_comment, filters) + parse_comments(&data["replies"], post_link, post_author, highlighted_comment, filters, req) } else { Vec::new() }; @@ -169,6 +169,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, awards, collapsed, is_filtered, + prefs: Preferences::new(req), } }) .collect() diff --git a/src/search.rs b/src/search.rs index 87965c3..1322e39 100644 --- a/src/search.rs +++ b/src/search.rs @@ -105,7 +105,7 @@ pub async fn find(req: Request) -> Result, String> { restrict_sr: param(&path, "restrict_sr").unwrap_or_default(), typed, }, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, is_filtered: true, all_posts_filtered: false, @@ -131,7 +131,7 @@ pub async fn find(req: Request) -> Result, String> { restrict_sr: param(&path, "restrict_sr").unwrap_or_default(), typed, }, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, is_filtered: false, all_posts_filtered, diff --git a/src/settings.rs b/src/settings.rs index 0fd2640..4aa0a09 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -19,7 +19,7 @@ struct SettingsTemplate { // CONSTANTS -const PREFS: [&str; 11] = [ +const PREFS: [&str; 12] = [ "theme", "front_page", "layout", @@ -31,6 +31,7 @@ const PREFS: [&str; 11] = [ "use_hls", "hide_hls_notification", "autoplay_videos", + "hide_awards", ]; // FUNCTIONS @@ -39,7 +40,7 @@ const PREFS: [&str; 11] = [ pub async fn get(req: Request) -> Result, String> { let url = req.uri().to_string(); template(SettingsTemplate { - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, }) } diff --git a/src/subreddit.rs b/src/subreddit.rs index ef511c2..ae9851a 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -109,7 +109,7 @@ pub async fn community(req: Request) -> Result, String> { posts: Vec::new(), sort: (sort, param(&path, "t").unwrap_or_default()), ends: (param(&path, "after").unwrap_or_default(), "".to_string()), - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, redirect_url, is_filtered: true, @@ -128,7 +128,7 @@ pub async fn community(req: Request) -> Result, String> { posts, sort: (sort, param(&path, "t").unwrap_or_default()), ends: (param(&path, "after").unwrap_or_default(), after), - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, redirect_url, is_filtered: false, @@ -153,7 +153,7 @@ pub fn quarantine(req: Request, sub: String) -> Result, Str msg: "Please click the button below to continue to this subreddit.".to_string(), url: req.uri().to_string(), sub, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), }; Ok( @@ -200,7 +200,7 @@ pub async fn subscriptions_filters(req: Request) -> Result, let query = req.uri().query().unwrap_or_default().to_string(); - let preferences = Preferences::new(req); + let preferences = Preferences::new(&req); let mut sub_list = preferences.subscriptions; let mut filters = preferences.filters; @@ -313,7 +313,7 @@ pub async fn wiki(req: Request) -> Result, String> { sub, wiki: rewrite_urls(response["data"]["content_html"].as_str().unwrap_or("

Wiki not found

")), page, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, }), Err(msg) => { @@ -351,7 +351,7 @@ pub async fn sidebar(req: Request) -> Result, String> { // ), sub, page: "Sidebar".to_string(), - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, }), Err(msg) => { diff --git a/src/user.rs b/src/user.rs index 6c991ef..3813728 100644 --- a/src/user.rs +++ b/src/user.rs @@ -56,7 +56,7 @@ pub async fn profile(req: Request) -> Result, String> { sort: (sort, param(&path, "t").unwrap_or_default()), ends: (param(&path, "after").unwrap_or_default(), "".to_string()), listing, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, redirect_url, is_filtered: true, @@ -77,7 +77,7 @@ pub async fn profile(req: Request) -> Result, String> { sort: (sort, param(&path, "t").unwrap_or_default()), ends: (param(&path, "after").unwrap_or_default(), after), listing, - prefs: Preferences::new(req), + prefs: Preferences::new(&req), url, redirect_url, is_filtered: false, diff --git a/src/utils.rs b/src/utils.rs index 06237e9..8badd6e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -357,6 +357,7 @@ pub struct Comment { pub awards: Awards, pub collapsed: bool, pub is_filtered: bool, + pub prefs: Preferences, } #[derive(Default, Clone)] @@ -472,6 +473,7 @@ pub struct Preferences { pub post_sort: String, pub subscriptions: Vec, pub filters: Vec, + pub hide_awards: String, } #[derive(RustEmbed)] @@ -481,7 +483,7 @@ pub struct ThemeAssets; impl Preferences { // Build preferences from cookies - pub fn new(req: Request) -> Self { + pub fn new(req: &Request) -> Self { // Read available theme names from embedded css files. // Always make the default "system" theme available. let mut themes = vec!["system".to_string()]; @@ -504,6 +506,7 @@ impl Preferences { post_sort: setting(&req, "post_sort"), subscriptions: setting(&req, "subscriptions").split('+').map(String::from).filter(|s| !s.is_empty()).collect(), filters: setting(&req, "filters").split('+').map(String::from).filter(|s| !s.is_empty()).collect(), + hide_awards: setting(&req, "hide_awards"), } } } @@ -820,7 +823,7 @@ pub async fn error(req: Request, msg: impl ToString) -> Result{{ rel_time }}
{% if edited.0 != "".to_string() %}edited {{ edited.0 }}{% endif %} - {% if !awards.is_empty() %} + {% if !awards.is_empty() && prefs.hide_awards != "on" %} {% for award in awards.clone() %} diff --git a/templates/duplicates.html b/templates/duplicates.html index db6afc7..4344325 100644 --- a/templates/duplicates.html +++ b/templates/duplicates.html @@ -65,7 +65,7 @@ {{ post.rel_time }} - {% if !post.awards.is_empty() %} + {% if !post.awards.is_empty() && prefs.hide_awards != "on" %} {% for award in post.awards.clone() %} {{ award.name }} @@ -104,4 +104,4 @@ {% endif %}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/settings.html b/templates/settings.html index b4bab8c..1df8c1f 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -83,6 +83,11 @@
+
+ + + +
diff --git a/templates/utils.html b/templates/utils.html index 639b0d8..a1095d2 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -73,7 +73,7 @@ {% endif %} {{ post.rel_time }} - {% if !post.awards.is_empty() %} + {% if !post.awards.is_empty() && prefs.hide_awards != "on" %} {% for award in post.awards.clone() %} @@ -178,7 +178,7 @@ {{ post.rel_time }} - {% if !post.awards.is_empty() %} + {% if !post.awards.is_empty() && prefs.hide_awards != "on" %} {% for award in post.awards.clone() %} {{ award.name }} From c15f305be0c97730f91694146c493fdccdc3371e Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Sun, 1 Jan 2023 23:54:35 -0700 Subject: [PATCH 77/92] v0.25.3 --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f52164a..e947b07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.25.2" +version = "0.25.3" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index cc7f517..1375851 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.25.2" +version = "0.25.3" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" @@ -35,4 +35,4 @@ lipsum = "0.8.2" [profile.release] codegen-units = 1 lto = true -strip = true \ No newline at end of file +strip = true From c83a4e0cc87ef82e2fc4ea9031393533744a3d54 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 3 Jan 2023 02:39:45 -0700 Subject: [PATCH 78/92] Landing page for NSFW content, SFW-only mode (#656) Co-authored-by: Matt Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- README.md | 12 +++++- app.json | 3 ++ src/duplicates.rs | 12 +++++- src/post.rs | 10 ++++- src/search.rs | 9 ++++- src/subreddit.rs | 9 ++++- src/user.rs | 12 +++++- src/utils.rs | 82 ++++++++++++++++++++++++++++++++++++++ static/style.css | 52 ++++++++++++++++++++++-- templates/base.html | 5 +++ templates/nsfwlanding.html | 28 +++++++++++++ templates/settings.html | 6 +++ 12 files changed, 227 insertions(+), 13 deletions(-) create mode 100644 templates/nsfwlanding.html diff --git a/README.md b/README.md index 891e6c9..5f3c647 100644 --- a/README.md +++ b/README.md @@ -182,9 +182,17 @@ Once installed, deploy Libreddit to `0.0.0.0:8080` by running: libreddit ``` -## Change Default Settings +## Instance settings -Assign a default value for each setting by passing environment variables to Libreddit in the format `LIBREDDIT_DEFAULT_{X}`. Replace `{X}` with the setting name (see list below) in capital letters. +Assign a default value for each instance-specific setting by passing environment variables to Libreddit in the format `LIBREDDIT_{X}`. Replace `{X}` with the setting name (see list below) in capital letters. + +|Name|Possible values|Default value|Description| +|-|-|-|-| +| `SFW_ONLY` | `["on", "off"]` | `off` | Enables SFW-only mode for the instance, i.e. all NSFW content is filtered. | + +## Default User Settings + +Assign a default value for each user-modifiable setting by passing environment variables to Libreddit in the format `LIBREDDIT_DEFAULT_{Y}`. Replace `{Y}` with the setting name (see list below) in capital letters. | Name | Possible values | Default value | |-------------------------|-----------------------------------------------------------------------------------------------------|---------------| diff --git a/app.json b/app.json index fd41fc8..48b6f1d 100644 --- a/app.json +++ b/app.json @@ -40,6 +40,9 @@ }, "LIBREDDIT_HIDE_HLS_NOTIFICATION": { "required": false + }, + "LIBREDDIT_SFW_ONLY": { + "required": false } } } diff --git a/src/duplicates.rs b/src/duplicates.rs index 6a64fc8..d68d1b3 100644 --- a/src/duplicates.rs +++ b/src/duplicates.rs @@ -3,7 +3,7 @@ use crate::client::json; use crate::server::RequestExt; use crate::subreddit::{can_access_quarantine, quarantine}; -use crate::utils::{error, filter_posts, get_filters, parse_post, template, Post, Preferences}; +use crate::utils::{error, filter_posts, get_filters, nsfw_landing, parse_post, setting, template, Post, Preferences}; use askama::Template; use hyper::{Body, Request, Response}; @@ -65,8 +65,16 @@ pub async fn item(req: Request) -> Result, String> { match json(path, quarantined).await { // Process response JSON. Ok(response) => { - let filters = get_filters(&req); let post = parse_post(&response[0]["data"]["children"][0]).await; + + // Return landing page if this post if this Reddit deems this post + // NSFW, but we have also disabled the display of NSFW content + // or if the instance is SFW-only. + if post.nsfw && (setting(&req, "show_nsfw") != "on" || crate::utils::sfw_only()) { + return Ok(nsfw_landing(req).await.unwrap_or_default()); + } + + let filters = get_filters(&req); let (duplicates, num_posts_filtered, all_posts_filtered) = parse_duplicates(&response[1], &filters).await; // These are the values for the "before=", "after=", and "sort=" diff --git a/src/post.rs b/src/post.rs index e467fe7..1423e60 100644 --- a/src/post.rs +++ b/src/post.rs @@ -3,7 +3,7 @@ use crate::client::json; use crate::server::RequestExt; use crate::subreddit::{can_access_quarantine, quarantine}; use crate::utils::{ - error, format_num, get_filters, param, parse_post, rewrite_urls, setting, template, time, val, Author, Awards, Comment, Flair, FlairPart, Post, Preferences, + error, format_num, get_filters, nsfw_landing, param, parse_post, rewrite_urls, setting, template, time, val, Author, Awards, Comment, Flair, FlairPart, Post, Preferences, }; use hyper::{Body, Request, Response}; @@ -55,6 +55,14 @@ pub async fn item(req: Request) -> Result, String> { Ok(response) => { // Parse the JSON into Post and Comment structs let post = parse_post(&response[0]["data"]["children"][0]).await; + + // Return landing page if this post if this Reddit deems this post + // NSFW, but we have also disabled the display of NSFW content + // or if the instance is SFW-only. + if post.nsfw && (setting(&req, "show_nsfw") != "on" || crate::utils::sfw_only()) { + return Ok(nsfw_landing(req).await.unwrap_or_default()); + } + let comments = parse_comments(&response[1], &post.permalink, &post.author.name, highlighted_comment, &get_filters(&req)); let url = req.uri().to_string(); diff --git a/src/search.rs b/src/search.rs index 87965c3..7158fdc 100644 --- a/src/search.rs +++ b/src/search.rs @@ -1,5 +1,5 @@ // CRATES -use crate::utils::{catch_random, error, filter_posts, format_num, format_url, get_filters, param, redirect, setting, template, val, Post, Preferences}; +use crate::utils::{self, catch_random, error, filter_posts, format_num, format_url, get_filters, param, redirect, setting, template, val, Post, Preferences}; use crate::{ client::json, subreddit::{can_access_quarantine, quarantine}, @@ -54,7 +54,12 @@ static REDDIT_URL_MATCH: Lazy = Lazy::new(|| Regex::new(r"^https?://([^\. // SERVICES pub async fn find(req: Request) -> Result, String> { - let nsfw_results = if setting(&req, "show_nsfw") == "on" { "&include_over_18=on" } else { "" }; + // This ensures that during a search, no NSFW posts are fetched at all + let nsfw_results = if setting(&req, "show_nsfw") == "on" && !utils::sfw_only() { + "&include_over_18=on" + } else { + "" + }; let path = format!("{}.json?{}{}&raw_json=1", req.uri().path(), req.uri().query().unwrap_or_default(), nsfw_results); let mut query = param(&path, "q").unwrap_or_default(); query = REDDIT_URL_MATCH.replace(&query, "").to_string(); diff --git a/src/subreddit.rs b/src/subreddit.rs index ef511c2..af87d93 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -1,6 +1,6 @@ // CRATES use crate::utils::{ - catch_random, error, filter_posts, format_num, format_url, get_filters, param, redirect, rewrite_urls, setting, template, val, Post, Preferences, Subreddit, + catch_random, error, filter_posts, format_num, format_url, get_filters, nsfw_landing, param, redirect, rewrite_urls, setting, template, val, Post, Preferences, Subreddit, }; use crate::{client::json, server::ResponseExt, RequestExt}; use askama::Template; @@ -97,6 +97,12 @@ pub async fn community(req: Request) -> Result, String> { } }; + // Return landing page if this post if this is NSFW community but the user + // has disabled the display of NSFW content or if the instance is SFW-only. + if sub.nsfw && (setting(&req, "show_nsfw") != "on" || crate::utils::sfw_only()) { + return Ok(nsfw_landing(req).await.unwrap_or_default()); + } + let path = format!("/r/{}/{}.json?{}&raw_json=1", sub_name.clone(), sort, req.uri().query().unwrap_or_default()); let url = String::from(req.uri().path_and_query().map_or("", |val| val.as_str())); let redirect_url = url[1..].replace('?', "%3F").replace('&', "%26").replace('+', "%2B"); @@ -424,5 +430,6 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result { members: format_num(members), active: format_num(active), wiki: res["data"]["wiki_enabled"].as_bool().unwrap_or_default(), + nsfw: res["data"]["over18"].as_bool().unwrap_or_default(), }) } diff --git a/src/user.rs b/src/user.rs index 6c991ef..3620fce 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,7 +1,7 @@ // CRATES use crate::client::json; use crate::server::RequestExt; -use crate::utils::{error, filter_posts, format_url, get_filters, param, setting, template, Post, Preferences, User}; +use crate::utils::{error, filter_posts, format_url, get_filters, nsfw_landing, param, setting, template, Post, Preferences, User}; use askama::Template; use hyper::{Body, Request, Response}; use time::{macros::format_description, OffsetDateTime}; @@ -46,8 +46,17 @@ pub async fn profile(req: Request) -> Result, String> { // Retrieve other variables from Libreddit request let sort = param(&path, "sort").unwrap_or_default(); let username = req.param("name").unwrap_or_default(); + + // Retrieve info from user about page. let user = user(&username).await.unwrap_or_default(); + // Return landing page if this post if this Reddit deems this user NSFW, + // but we have also disabled the display of NSFW content or if the instance + // is SFW-only. + if user.nsfw && (setting(&req, "show_nsfw") != "on" || crate::utils::sfw_only()) { + return Ok(nsfw_landing(req).await.unwrap_or_default()); + } + let filters = get_filters(&req); if filters.contains(&["u_", &username].concat()) { template(UserTemplate { @@ -115,6 +124,7 @@ async fn user(name: &str) -> Result { created: created.format(format_description!("[month repr:short] [day] '[year repr:last_two]")).unwrap_or_default(), banner: about("banner_img"), description: about("public_description"), + nsfw: res["data"]["subreddit"]["over_18"].as_bool().unwrap_or_default(), } }) } diff --git a/src/utils.rs b/src/utils.rs index 06237e9..fee97e9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,6 +9,7 @@ use regex::Regex; use rust_embed::RustEmbed; use serde_json::Value; use std::collections::{HashMap, HashSet}; +use std::env; use std::str::FromStr; use time::{macros::format_description, Duration, OffsetDateTime}; use url::Url; @@ -28,6 +29,16 @@ macro_rules! dbg_msg { }; } +/// Identifies whether or not the page is a subreddit, a user page, or a post. +/// This is used by the NSFW landing template to determine the mesage to convey +/// to the user. +#[derive(PartialEq, Eq)] +pub enum ResourceType { + Subreddit, + User, + Post, +} + // Post flair with content, background color and foreground color pub struct Flair { pub flair_parts: Vec, @@ -229,6 +240,7 @@ pub struct Post { pub comments: (String, String), pub gallery: Vec, pub awards: Awards, + pub nsfw: bool, } impl Post { @@ -329,6 +341,7 @@ impl Post { comments: format_num(data["num_comments"].as_i64().unwrap_or_default()), gallery, awards, + nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(), }); } @@ -420,6 +433,27 @@ pub struct ErrorTemplate { pub url: String, } +/// Template for NSFW landing page. The landing page is displayed when a page's +/// content is wholly NSFW, but a user has not enabled the option to view NSFW +/// posts. +#[derive(Template)] +#[template(path = "nsfwlanding.html")] +pub struct NSFWLandingTemplate { + /// Identifier for the resource. This is either a subreddit name or a + /// username. (In the case of the latter, set is_user to true.) + pub res: String, + + /// Identifies whether or not the resource is a subreddit, a user page, + /// or a post. + pub res_type: ResourceType, + + /// User preferences. + pub prefs: Preferences, + + /// Request URL. + pub url: String, +} + #[derive(Default)] // User struct containing metadata about user pub struct User { @@ -430,6 +464,7 @@ pub struct User { pub created: String, pub banner: String, pub description: String, + pub nsfw: bool, } #[derive(Default)] @@ -444,6 +479,7 @@ pub struct Subreddit { pub members: (String, String), pub active: (String, String), pub wiki: bool, + pub nsfw: bool, } // Parser for query params, used in sorting (eg. /r/rust/?sort=hot) @@ -617,6 +653,7 @@ pub async fn parse_post(post: &serde_json::Value) -> Post { comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), gallery, awards, + nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(), } } @@ -829,6 +866,51 @@ pub async fn error(req: Request, msg: impl ToString) -> Result bool { + match env::var("LIBREDDIT_SFW_ONLY") { + Ok(val) => val == "on", + Err(_) => false, + } +} + +/// Renders the landing page for NSFW content when the user has not enabled +/// "show NSFW posts" in settings. +pub async fn nsfw_landing(req: Request) -> Result, String> { + let res_type: ResourceType; + let url = req.uri().to_string(); + + // Determine from the request URL if the resource is a subreddit, a user + // page, or a post. + let res: String = if !req.param("name").unwrap_or_default().is_empty() { + res_type = ResourceType::User; + req.param("name").unwrap_or_default() + } else if !req.param("id").unwrap_or_default().is_empty() { + res_type = ResourceType::Post; + req.param("id").unwrap_or_default() + } else { + res_type = ResourceType::Subreddit; + req.param("sub").unwrap_or_default() + }; + + let body = NSFWLandingTemplate { + res, + res_type, + prefs: Preferences::new(req), + url, + } + .render() + .unwrap_or_default(); + + Ok(Response::builder().status(403).header("content-type", "text/html").body(body.into()).unwrap_or_default()) +} + #[cfg(test)] mod tests { use super::{format_num, format_url, rewrite_urls}; diff --git a/static/style.css b/static/style.css index a0d4b69..05c493a 100644 --- a/static/style.css +++ b/static/style.css @@ -160,16 +160,35 @@ main { overflow: inherit; } -footer { +/* Body footer. */ +body > footer { + display: flex; + justify-content: center; + margin: 20px; +} + +body > footer > div#sfw-only { + color: var(--green); + border: 1px solid var(--green); + padding: 5px; + box-sizing: border-box; + border-radius: 5px; +} +/* / Body footer. */ + +/* Footer in content block. */ +main > * > footer { display: flex; justify-content: center; margin-top: 20px; } -footer > a { +main > * > footer > a { margin-right: 5px; } +/* / Footer in content block. */ + button { background: none; border: none; @@ -485,7 +504,7 @@ button.submit:hover > svg { stroke: var(--accent); } overflow-x: auto; } -#sort_options, #listing_options, footer > a { +#sort_options, #listing_options, main > * > footer > a { border-radius: 5px; align-items: center; box-shadow: var(--shadow); @@ -494,7 +513,7 @@ button.submit:hover > svg { stroke: var(--accent); } overflow: hidden; } -#sort_options > a, #listing_options > a, footer > a { +#sort_options > a, #listing_options > a, main > * > footer > a { color: var(--text); padding: 10px 20px; text-align: center; @@ -1315,6 +1334,31 @@ td, th { color: var(--accent); } +/* NSFW Landing Page */ + +#nsfw_landing { + display: inline-block; + text-align: center; + width: 100%; +} + +#nsfw_landing h1 { + display: inline-block; + margin-bottom: 20px; + text-align: center; + width: 100%; +} + +#nsfw_landing p { + display: inline-block; + text-align: center; + width: 100%; +} + +#nsfw_landing a { + color: var(--accent); +} + /* Mobile */ @media screen and (max-width: 800px) { diff --git a/templates/base.html b/templates/base.html index bbea3bf..dd882d8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -65,5 +65,10 @@ {% endblock %} {% endblock %} + {% block footer %} + {% if crate::utils::sfw_only() %} +
This instance of Libreddit is SFW-only.
+ {% endif %} + {% endblock %} diff --git a/templates/nsfwlanding.html b/templates/nsfwlanding.html new file mode 100644 index 0000000..f6287a3 --- /dev/null +++ b/templates/nsfwlanding.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% block title %}NSFW content gated{% endblock %} +{% block sortstyle %}{% endblock %} +{% block content %} +
+

+ 😱 + {% if res_type == crate::utils::ResourceType::Subreddit %} + r/{{ res }} is a NSFW community! + {% else if res_type == crate::utils::ResourceType::User %} + u/{{ res }}'s content is NSFW! + {% else if res_type == crate::utils::ResourceType::Post %} + This post is NSFW! + {% endif %} +

+
+ +

+ {% if crate::utils::sfw_only() %} + This instance of Libreddit is SFW-only.

+ {% else %} + Enable "Show NSFW posts" in settings to view this {% if res_type == crate::utils::ResourceType::Subreddit %}subreddit{% else if res_type == crate::utils::ResourceType::User %}user's posts or comments{% else if res_type == crate::utils::ResourceType::Post %}post{% endif %}. + {% endif %} +

+
+{% endblock %} +{% block footer %} +{% endblock %} diff --git a/templates/settings.html b/templates/settings.html index b4bab8c..530176e 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -54,6 +54,7 @@ {% call utils::options(prefs.comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %} + {% if !crate::utils::sfw_only() %}
@@ -64,6 +65,7 @@
+ {% endif %}
@@ -121,6 +123,10 @@

Note: settings and subscriptions are saved in browser cookies. Clearing your cookies will reset them.


You can restore your current settings and subscriptions after clearing your cookies using this link.

+
+ {% if crate::utils::sfw_only() %} +

This instance is SFW-only. It will block all NSFW content.

+ {% endif %}
From 4817f51bc0d0b499ec1123b4d930bfb588e8334a Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 3 Jan 2023 02:40:44 -0700 Subject: [PATCH 79/92] v0.26.0 --- CREDITS | 4 ++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 0d7d117..a026e0b 100644 --- a/CREDITS +++ b/CREDITS @@ -21,11 +21,13 @@ dbrennand <52419383+dbrennand@users.noreply.github.com> Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com> Dyras Edward <101938856+EdwardLangdon@users.noreply.github.com> +elliot <75391956+ellieeet123@users.noreply.github.com> erdnaxe Esmail EL BoB FireMasterK <20838718+FireMasterK@users.noreply.github.com> George Roubos git-bruh +gmnsii <95436780+gmnsii@users.noreply.github.com> guaddy <67671414+guaddy@users.noreply.github.com> Harsh Mishra igna @@ -62,11 +64,13 @@ robrobinbin <> robrobinbin <8597693+robrobinbin@users.noreply.github.com> robrobinbin Ruben Elshof <15641671+rubenelshof@users.noreply.github.com> +Rupert Angermeier Scoder12 <34356756+Scoder12@users.noreply.github.com> Slayer <51095261+GhostSlayer@users.noreply.github.com> Soheb somini somoso +Spenser Black Spike <19519553+spikecodes@users.noreply.github.com> spikecodes <19519553+spikecodes@users.noreply.github.com> sybenx diff --git a/Cargo.lock b/Cargo.lock index e947b07..287700c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.25.3" +version = "0.26.0" dependencies = [ "askama", "async-recursion", diff --git a/Cargo.toml b/Cargo.toml index 1375851..680e7ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.25.3" +version = "0.26.0" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 5b06a3fc648ad9ed4f7db7a5d59b1af909d2c03d Mon Sep 17 00:00:00 2001 From: Matthew E Date: Tue, 3 Jan 2023 04:55:22 -0500 Subject: [PATCH 80/92] Add config system to read from file (#664) Co-authored-by: Daniel Valentine --- Cargo.lock | 163 ++++++++++++++++++++++++++++++++++++++------------ Cargo.toml | 2 + README.md | 7 +++ src/config.rs | 130 ++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/utils.rs | 12 ++-- 6 files changed, 272 insertions(+), 43 deletions(-) create mode 100644 src/config.rs diff --git a/Cargo.lock b/Cargo.lock index 287700c..53d7bf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" dependencies = [ "proc-macro2", "quote", @@ -168,9 +168,9 @@ checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cached" @@ -211,9 +211,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" -version = "1.0.76" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" [[package]] name = "cfg-if" @@ -223,9 +223,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.0.24" +version = "4.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60494cedb60cb47462c0ff7be53de32c0e42a6fc2c772184554fa12bd9489c03" +checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" dependencies = [ "bitflags", "clap_lex", @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -363,6 +363,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + [[package]] name = "futures" version = "0.3.25" @@ -567,9 +573,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -598,9 +604,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -638,9 +644,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "libflate" @@ -682,10 +688,12 @@ dependencies = [ "regex", "route-recognizer", "rust-embed", + "sealed_test", "serde", "serde_json", "time", "tokio", + "toml", "url", ] @@ -792,9 +800,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.4.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "parking" @@ -814,9 +822,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ "cfg-if", "libc", @@ -858,6 +866,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.21" @@ -923,6 +937,15 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "ring" version = "0.16.20" @@ -1018,6 +1041,18 @@ dependencies = [ "base64", ] +[[package]] +name = "rusty-forkfork" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce85af4dfa2fb0c0143121ab5e424c71ea693867357c9159b8777b59984c218" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.11" @@ -1059,6 +1094,28 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sealed_test" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a608d94641cc17fe203b102db2ae86d47a236630192f0244ddbbbb0044c0272" +dependencies = [ + "fs_extra", + "rusty-forkfork", + "sealed_test_derive", + "tempfile", +] + +[[package]] +name = "sealed_test_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b672e005ae58fef5da619d90b9f1c5b44b061890f4a371b3c96257a8a15e697" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "security-framework" version = "2.7.0" @@ -1084,18 +1141,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" dependencies = [ "proc-macro2", "quote", @@ -1104,9 +1161,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -1172,15 +1229,29 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "thiserror" version = "1.0.37" @@ -1245,9 +1316,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" dependencies = [ "autocfg", "bytes", @@ -1260,14 +1331,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -1299,6 +1370,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1333,9 +1413,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicase" @@ -1390,6 +1470,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 680e7ad..8d90338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,10 +27,12 @@ url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } libflate = "1.2.0" brotli = { version = "3.3.4", features = ["std"] } +toml = "0.5.9" once_cell = "1.16.0" [dev-dependencies] lipsum = "0.8.2" +sealed_test = "1.0.0" [profile.release] codegen-units = 1 diff --git a/README.md b/README.md index 5f3c647..7386272 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,13 @@ Assign a default value for each user-modifiable setting by passing environment v | `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` | | `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` | +You can also configure Libreddit with a configuration file. An example `libreddit.toml` can be found below: + +```toml +LIBREDDIT_DEFAULT_WIDE = "on" +LIBREDDIT_DEFAULT_USE_HLS = "on" +``` + ### Examples ```bash diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..c2d2055 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,130 @@ +use once_cell::sync::Lazy; +use std::{env::var, fs::read_to_string}; + +// Waiting for https://github.com/rust-lang/rust/issues/74465 to land, so we +// can reduce reliance on once_cell. +// +// This is the local static that is initialized at runtime (technically at +// first request) and contains the instance settings. +static CONFIG: Lazy = Lazy::new(Config::load); + +/// Stores the configuration parsed from the environment variables and the +/// config file. `Config::Default()` contains None for each setting. +#[derive(Default, serde::Deserialize)] +pub struct Config { + #[serde(rename = "LIBREDDIT_SFW_ONLY")] + sfw_only: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_THEME")] + default_theme: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_FRONT_PAGE")] + default_front_page: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_LAYOUT")] + default_layout: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_WIDE")] + default_wide: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_COMMENT_SORT")] + default_comment_sort: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_POST_SORT")] + default_post_sort: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_SHOW_NSFW")] + default_show_nsfw: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_BLUR_NSFW")] + default_blur_nsfw: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_USE_HLS")] + default_use_hls: Option, + + #[serde(rename = "LIBREDDIT_DEFAULT_HIDE_HLS_NOTIFICATION")] + default_hide_hls_notification: Option, +} + +impl Config { + /// Load the configuration from the environment variables and the config file. + /// In the case that there are no environment variables set and there is no + /// config file, this function returns a Config that contains all None values. + pub fn load() -> Self { + // Read from libreddit.toml config file. If for any reason, it fails, the + // default `Config` is used (all None values) + let config: Config = toml::from_str(&read_to_string("libreddit.toml").unwrap_or_default()).unwrap_or_default(); + // This function defines the order of preference - first check for + // environment variables with "LIBREDDIT", then check the config, then if + // both are `None`, return a `None` via the `map_or_else` function + let parse = |key: &str| -> Option { var(key).ok().map_or_else(|| get_setting_from_config(key, &config), Some) }; + Self { + sfw_only: parse("LIBREDDIT_SFW_ONLY"), + default_theme: parse("LIBREDDIT_DEFAULT_THEME"), + default_front_page: parse("LIBREDDIT_DEFAULT_FRONT_PAGE"), + default_layout: parse("LIBREDDIT_DEFAULT_LAYOUT"), + default_post_sort: parse("LIBREDDIT_DEFAULT_POST_SORT"), + default_wide: parse("LIBREDDIT_DEFAULT_WIDE"), + default_comment_sort: parse("LIBREDDIT_DEFAULT_COMMENT_SORT"), + default_show_nsfw: parse("LIBREDDIT_DEFAULT_SHOW_NSFW"), + default_blur_nsfw: parse("LIBREDDIT_DEFAULT_BLUR_NSFW"), + default_use_hls: parse("LIBREDDIT_DEFAULT_USE_HLS"), + default_hide_hls_notification: parse("LIBREDDIT_DEFAULT_HIDE_HLS"), + } + } +} + +fn get_setting_from_config(name: &str, config: &Config) -> Option { + match name { + "LIBREDDIT_SFW_ONLY" => config.sfw_only.clone(), + "LIBREDDIT_DEFAULT_THEME" => config.default_theme.clone(), + "LIBREDDIT_DEFAULT_FRONT_PAGE" => config.default_front_page.clone(), + "LIBREDDIT_DEFAULT_LAYOUT" => config.default_layout.clone(), + "LIBREDDIT_DEFAULT_COMMENT_SORT" => config.default_comment_sort.clone(), + "LIBREDDIT_DEFAULT_POST_SORT" => config.default_post_sort.clone(), + "LIBREDDIT_DEFAULT_SHOW_NSFW" => config.default_show_nsfw.clone(), + "LIBREDDIT_DEFAULT_BLUR_NSFW" => config.default_blur_nsfw.clone(), + "LIBREDDIT_DEFAULT_USE_HLS" => config.default_use_hls.clone(), + "LIBREDDIT_DEFAULT_HIDE_HLS_NOTIFICATION" => config.default_hide_hls_notification.clone(), + "LIBREDDIT_DEFAULT_WIDE" => config.default_wide.clone(), + _ => None, + } +} + +/// Retrieves setting from environment variable or config file. +pub(crate) fn get_setting(name: &str) -> Option { + get_setting_from_config(name, &CONFIG) +} + +#[cfg(test)] +use {sealed_test::prelude::*, std::fs::write}; + +#[test] +#[sealed_test(env = [("LIBREDDIT_SFW_ONLY", "1")])] +fn test_env_var() { + assert!(crate::utils::sfw_only()) +} + +#[test] +#[sealed_test] +fn test_config() { + let config_to_write = r#"LIBREDDIT_DEFAULT_COMMENT_SORT = "best""#; + write("libreddit.toml", config_to_write).unwrap(); + assert_eq!(get_setting("LIBREDDIT_DEFAULT_COMMENT_SORT"), Some("best".into())); +} + +#[test] +#[sealed_test(env = [("LIBREDDIT_DEFAULT_COMMENT_SORT", "top")])] +fn test_env_config_precedence() { + let config_to_write = r#"LIBREDDIT_DEFAULT_COMMENT_SORT = "best""#; + write("libreddit.toml", config_to_write).unwrap(); + assert_eq!(get_setting("LIBREDDIT_DEFAULT_COMMENT_SORT"), Some("top".into())) +} + +#[test] +#[sealed_test(env = [("LIBREDDIT_DEFAULT_COMMENT_SORT", "top")])] +fn test_alt_env_config_precedence() { + let config_to_write = r#"LIBREDDIT_DEFAULT_COMMENT_SORT = "best""#; + write("libreddit.toml", config_to_write).unwrap(); + assert_eq!(get_setting("LIBREDDIT_DEFAULT_COMMENT_SORT"), Some("top".into())) +} diff --git a/src/main.rs b/src/main.rs index 25c2aea..bffe99c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ #![allow(clippy::cmp_owned)] // Reference local files +mod config; mod duplicates; mod post; mod search; diff --git a/src/utils.rs b/src/utils.rs index fee97e9..8c8d273 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -680,8 +680,8 @@ pub fn setting(req: &Request, name: &str) -> String { req .cookie(name) .unwrap_or_else(|| { - // If there is no cookie for this setting, try receiving a default from an environment variable - if let Ok(default) = std::env::var(format!("LIBREDDIT_DEFAULT_{}", name.to_uppercase())) { + // If there is no cookie for this setting, try receiving a default from the config + if let Some(default) = crate::config::get_setting(&format!("LIBREDDIT_DEFAULT_{}", name.to_uppercase())) { Cookie::new(name, default) } else { Cookie::named(name) @@ -866,7 +866,7 @@ pub async fn error(req: Request, msg: impl ToString) -> Result, msg: impl ToString) -> Result bool { - match env::var("LIBREDDIT_SFW_ONLY") { - Ok(val) => val == "on", - Err(_) => false, + match crate::config::get_setting("LIBREDDIT_SFW_ONLY") { + Some(val) => val == "on", + None => false, } } From 050eaedf15d2fd611f4c623da2629f22e5cc36cd Mon Sep 17 00:00:00 2001 From: Tokarak <63452145+Tokarak@users.noreply.github.com> Date: Tue, 3 Jan 2023 14:56:17 +0000 Subject: [PATCH 81/92] Remove unused dep "async-recursion" Found using cargo-udeps. Checked. --- Cargo.lock | 12 ------------ Cargo.toml | 1 - 2 files changed, 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53d7bf9..a3865f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,17 +75,6 @@ dependencies = [ "syn", ] -[[package]] -name = "async-recursion" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-trait" version = "0.1.59" @@ -673,7 +662,6 @@ name = "libreddit" version = "0.26.0" dependencies = [ "askama", - "async-recursion", "brotli", "cached", "clap", diff --git a/Cargo.toml b/Cargo.toml index 8d90338..3554806 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" [dependencies] askama = { version = "0.11.1", default-features = false } -async-recursion = "1.0.0" cached = "0.40.0" clap = { version = "4.0.24", default-features = false, features = ["std"] } regex = "1.7.0" From e9891236cde5a84ffb8cb4d76c3f5f4195cbaf98 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 3 Jan 2023 11:20:55 -0700 Subject: [PATCH 82/92] Remove unnecessary SFW-only disclosure in settings in SFW-only mode. --- templates/settings.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/templates/settings.html b/templates/settings.html index 2f7eb9a..2b4f804 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -128,10 +128,6 @@

Note: settings and subscriptions are saved in browser cookies. Clearing your cookies will reset them.


You can restore your current settings and subscriptions after clearing your cookies using this link.

-
- {% if crate::utils::sfw_only() %} -

This instance is SFW-only. It will block all NSFW content.

- {% endif %}
From 0ff92cbfe33e9c6b9bdfcc94773eb6d1c6e8d0ca Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Tue, 3 Jan 2023 11:21:27 -0700 Subject: [PATCH 83/92] v0.27.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3865f1..1900bf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,7 +659,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.26.0" +version = "0.27.0" dependencies = [ "askama", "brotli", diff --git a/Cargo.toml b/Cargo.toml index 3554806..40b3577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.26.0" +version = "0.27.0" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From f6bb53e388ce4346c6b8bf1b521983643f4d8183 Mon Sep 17 00:00:00 2001 From: Matthew E Date: Tue, 3 Jan 2023 23:55:17 -0500 Subject: [PATCH 84/92] Mark search query as safe in askama template (#686) --- templates/search.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/search.html b/templates/search.html index b9742f6..f4ecc58 100644 --- a/templates/search.html +++ b/templates/search.html @@ -10,7 +10,7 @@ {% block content %}
- + {% if sub != "" %}
From dff91da8777dc42d38abf8b5d63addbd71fdabff Mon Sep 17 00:00:00 2001 From: Johannes Schleifenbaum Date: Wed, 4 Jan 2023 11:12:19 +0100 Subject: [PATCH 85/92] config: fix SFW test --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index c2d2055..55a4580 100644 --- a/src/config.rs +++ b/src/config.rs @@ -100,7 +100,7 @@ pub(crate) fn get_setting(name: &str) -> Option { use {sealed_test::prelude::*, std::fs::write}; #[test] -#[sealed_test(env = [("LIBREDDIT_SFW_ONLY", "1")])] +#[sealed_test(env = [("LIBREDDIT_SFW_ONLY", "on")])] fn test_env_var() { assert!(crate::utils::sfw_only()) } From e238a7b168921397de9e841c73958fe5c555edd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jan 2023 01:39:23 -0700 Subject: [PATCH 86/92] Bump tokio from 1.23.0 to 1.23.1 (#691) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.23.0 to 1.23.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.23.0...tokio-1.23.1) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1900bf4..12ed5d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1304,9 +1304,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" dependencies = [ "autocfg", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 40b3577..1c8b7ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ hyper-rustls = "0.23.0" percent-encoding = "2.2.0" route-recognizer = "0.3.1" serde_json = "1.0.87" -tokio = { version = "1.21.2", features = ["full"] } +tokio = { version = "1.23.1", features = ["full"] } time = "0.3.17" url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } From 2a54043afc97acfd8f6c25af4a1eae0974708c56 Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Thu, 12 Jan 2023 03:41:59 -0500 Subject: [PATCH 87/92] Simplify listener definition (#681) This simplifies the logic to build the listener by using more clap features instead of manually accessing the PORT environment variable. This also removes unnecessary `unwrap_or` calls that set defaults that are already set by clap. --- Cargo.toml | 2 +- src/main.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c8b7ae..260f4a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] askama = { version = "0.11.1", default-features = false } cached = "0.40.0" -clap = { version = "4.0.24", default-features = false, features = ["std"] } +clap = { version = "4.0.24", default-features = false, features = ["std", "env"] } regex = "1.7.0" serde = { version = "1.0.147", features = ["derive"] } cookie = "0.16.1" diff --git a/src/main.rs b/src/main.rs index bffe99c..2d848ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod user; mod utils; // Import Crates -use clap::{Arg, Command}; +use clap::{Arg, ArgAction, Command}; use futures_lite::FutureExt; use hyper::{header::HeaderValue, Body, Request, Response}; @@ -130,8 +130,10 @@ async fn main() { .short('p') .long("port") .value_name("PORT") + .env("PORT") .help("Port to listen on") .default_value("8080") + .action(ArgAction::Set) .num_args(1), ) .arg( @@ -145,11 +147,11 @@ async fn main() { ) .get_matches(); - let address = matches.get_one("address").map(|m: &String| m.as_str()).unwrap_or("0.0.0.0"); - let port = std::env::var("PORT").unwrap_or_else(|_| matches.get_one("port").map(|m: &String| m.as_str()).unwrap_or("8080").to_string()); + let address = matches.get_one::("address").unwrap(); + let port = matches.get_one::("port").unwrap(); let hsts = matches.get_one("hsts").map(|m: &String| m.as_str()); - let listener = [address, ":", &port].concat(); + let listener = [address, ":", port].concat(); println!("Starting Libreddit..."); From 27091db53bb011baa98b15cc304f14b501ebe798 Mon Sep 17 00:00:00 2001 From: Matthew Esposito Date: Thu, 12 Jan 2023 03:43:08 -0500 Subject: [PATCH 88/92] Create rust-tests.yml (#690) This will run tests on every push and PR to master. --- .github/workflows/rust-tests.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/rust-tests.yml diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml new file mode 100644 index 0000000..c93aadf --- /dev/null +++ b/.github/workflows/rust-tests.yml @@ -0,0 +1,22 @@ +name: Tests + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose From 412122d7d923db6d1593ca4525d9a89a85953714 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 12 Jan 2023 01:56:03 -0700 Subject: [PATCH 89/92] v0.27.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12ed5d4..dedb5cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,7 +659,7 @@ dependencies = [ [[package]] name = "libreddit" -version = "0.27.0" +version = "0.27.1" dependencies = [ "askama", "brotli", diff --git a/Cargo.toml b/Cargo.toml index 260f4a1..7260f30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libreddit" description = " Alternative private front-end to Reddit" license = "AGPL-3.0" repository = "https://github.com/spikecodes/libreddit" -version = "0.27.0" +version = "0.27.1" authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"] edition = "2021" From 63b0b936aa46cab1016ea8d1c252390abe194d88 Mon Sep 17 00:00:00 2001 From: Daniel Valentine Date: Thu, 12 Jan 2023 02:19:09 -0700 Subject: [PATCH 90/92] Update CREDITS file. --- CREDITS | 67 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/CREDITS b/CREDITS index a026e0b..8c7c28d 100644 --- a/CREDITS +++ b/CREDITS @@ -1,86 +1,91 @@ 5trongthany <65565784+5trongthany@users.noreply.github.com> 674Y3r <87250374+674Y3r@users.noreply.github.com> -accountForIssues <52367365+accountForIssues@users.noreply.github.com> Adrian Lebioda -alefvanoon <53198048+alefvanoon@users.noreply.github.com> -alyaeanyx +Alexandre Iooss AndreVuillemot160 <84594011+AndreVuillemot160@users.noreply.github.com> Andrew Kaufman <57281817+andrew-kaufman@users.noreply.github.com> Artemis <51862164+artemislena@users.noreply.github.com> -arthomnix <35371030+arthomnix@users.noreply.github.com> Arya K <73596856+gi-yt@users.noreply.github.com> Austin Huang Basti Ben Smith <37027883+smithbm2316@users.noreply.github.com> BobIsMyManager -curlpipe <11898833+curlpipe@users.noreply.github.com> -dacousb <53299044+dacousb@users.noreply.github.com> Daniel Valentine Daniel Valentine -dbrennand <52419383+dbrennand@users.noreply.github.com> Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com> Dyras Edward <101938856+EdwardLangdon@users.noreply.github.com> -elliot <75391956+ellieeet123@users.noreply.github.com> -erdnaxe Esmail EL BoB FireMasterK <20838718+FireMasterK@users.noreply.github.com> George Roubos -git-bruh -gmnsii <95436780+gmnsii@users.noreply.github.com> -guaddy <67671414+guaddy@users.noreply.github.com> Harsh Mishra -igna -imabritishcow -Josiah <70736638+fres7h@users.noreply.github.com> JPyke3 +Johannes Schleifenbaum +Josiah <70736638+fres7h@users.noreply.github.com> Kavin <20838718+FireMasterK@users.noreply.github.com> Kazi Kieran <42723993+EnderDev@users.noreply.github.com> Kieran Kyle Roth -laazyCmd Laurenศ›iu Nicola Lena <102762572+MarshDeer@users.noreply.github.com> Macic <46872282+Macic-Dev@users.noreply.github.com> Mario A <10923513+Midblyte@users.noreply.github.com> Matthew Crossman Matthew E +Matthew Esposito Mennaruuk <52135169+Mennaruuk@users.noreply.github.com> -mikupls <93015331+mikupls@users.noreply.github.com> +NKIPSC <15067635+NKIPSC@users.noreply.github.com> Nainar Nathan Moos Nicholas Christopher Nick Lowery Nico -NKIPSC <15067635+NKIPSC@users.noreply.github.com> -obeho <71698631+obeho@users.noreply.github.com> -obscurity Om G <34579088+OxyMagnesium@users.noreply.github.com> RiversideRocks <59586759+RiversideRocks@users.noreply.github.com> -robin <8597693+robrobinbin@users.noreply.github.com> Robin <8597693+robrobinbin@users.noreply.github.com> -robrobinbin <> -robrobinbin <8597693+robrobinbin@users.noreply.github.com> -robrobinbin Ruben Elshof <15641671+rubenelshof@users.noreply.github.com> Rupert Angermeier Scoder12 <34356756+Scoder12@users.noreply.github.com> Slayer <51095261+GhostSlayer@users.noreply.github.com> Soheb -somini -somoso Spenser Black Spike <19519553+spikecodes@users.noreply.github.com> -spikecodes <19519553+spikecodes@users.noreply.github.com> -sybenx +The TwilightBlood TheCultLeader666 <65368815+TheCultLeader666@users.noreply.github.com> TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com> -The TwilightBlood -tirz <36501933+tirz@users.noreply.github.com> +Tokarak <63452145+Tokarak@users.noreply.github.com> Tsvetomir Bonev Vladislav Nepogodin Walkx Wichai <1482605+Chengings@users.noreply.github.com> -xatier Zach <72994911+zachjmurphy@users.noreply.github.com> +accountForIssues <52367365+accountForIssues@users.noreply.github.com> +alefvanoon <53198048+alefvanoon@users.noreply.github.com> +alyaeanyx +arthomnix <35371030+arthomnix@users.noreply.github.com> +curlpipe <11898833+curlpipe@users.noreply.github.com> +dacousb <53299044+dacousb@users.noreply.github.com> +dbrennand <52419383+dbrennand@users.noreply.github.com> +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +elliot <75391956+ellieeet123@users.noreply.github.com> +erdnaxe +git-bruh +gmnsii <95436780+gmnsii@users.noreply.github.com> +guaddy <67671414+guaddy@users.noreply.github.com> +igna +imabritishcow +laazyCmd +mikupls <93015331+mikupls@users.noreply.github.com> +obeho <71698631+obeho@users.noreply.github.com> +obscurity +robin <8597693+robrobinbin@users.noreply.github.com> +robrobinbin <8597693+robrobinbin@users.noreply.github.com> +robrobinbin <> +robrobinbin +somini +somoso +spikecodes <19519553+spikecodes@users.noreply.github.com> +sybenx +tirz <36501933+tirz@users.noreply.github.com> +xatier From 7cb132af01289187dcc07868be2997199bf4973b Mon Sep 17 00:00:00 2001 From: spikecodes <19519553+spikecodes@users.noreply.github.com> Date: Mon, 16 Jan 2023 11:09:57 -0800 Subject: [PATCH 91/92] Update packages --- Cargo.lock | 256 +++++++++++++++++++++++------------------------------ Cargo.toml | 20 ++--- 2 files changed, 120 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dedb5cf..af68e02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" dependencies = [ "proc-macro2", "quote", @@ -100,9 +100,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bitflags" @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -142,11 +142,12 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" dependencies = [ "memchr", + "serde", ] [[package]] @@ -163,16 +164,16 @@ checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cached" -version = "0.40.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b4147cd94d5fbdc2ab71b11d50a2f45493625576b3bb70257f59eedea69f3d" +checksum = "5e5877db5d1af7fae60d06b5db9430b68056a69b3582a0be8e3691e87654aeb6" dependencies = [ "async-trait", "async_once", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown", + "hashbrown 0.13.2", "instant", "lazy_static", "once_cell", @@ -182,12 +183,13 @@ dependencies = [ [[package]] name = "cached_proc_macro" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751f7f4e7a091545e7f6c65bacc404eaee7e87bfb1f9ece234a1caa173dc16f2" +checksum = "e10ca87c81aaa3a949dbbe2b5e6c2c45dbc94ba4897e45ea31ff9ec5087be3dc" dependencies = [ "cached_proc_macro_types", "darling", + "proc-macro2", "quote", "syn", ] @@ -200,9 +202,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" @@ -212,9 +214,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.0.29" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" +checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" dependencies = [ "bitflags", "clap_lex", @@ -222,18 +224,18 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] [[package]] name = "cookie" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "time", "version_check", @@ -285,9 +287,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ "darling_core", "darling_macro", @@ -295,9 +297,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ "fnv", "ident_case", @@ -309,9 +311,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", @@ -457,9 +459,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", "bstr", @@ -494,10 +496,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] @@ -598,7 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -612,9 +620,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" @@ -633,9 +641,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libflate" @@ -751,14 +759,14 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -766,9 +774,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ "hermit-abi", "libc", @@ -776,9 +784,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "openssl-probe" @@ -810,15 +818,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -847,9 +855,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -862,9 +870,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -910,9 +918,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -998,9 +1006,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -1022,9 +1030,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ "base64", ] @@ -1043,9 +1051,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "same-file" @@ -1058,12 +1066,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys", ] [[package]] @@ -1129,18 +1136,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.149" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.149" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -1149,9 +1156,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -1217,9 +1224,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1242,18 +1249,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -1304,9 +1311,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.23.1" +version = "1.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" +checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" dependencies = [ "autocfg", "bytes", @@ -1319,7 +1326,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1360,9 +1367,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] @@ -1395,9 +1402,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" @@ -1422,9 +1429,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -1605,19 +1612,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -1625,82 +1619,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/Cargo.toml b/Cargo.toml index 7260f30..784e7ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,25 +9,25 @@ edition = "2021" [dependencies] askama = { version = "0.11.1", default-features = false } -cached = "0.40.0" -clap = { version = "4.0.24", default-features = false, features = ["std", "env"] } -regex = "1.7.0" -serde = { version = "1.0.147", features = ["derive"] } -cookie = "0.16.1" +cached = "0.42.0" +clap = { version = "4.1.1", default-features = false, features = ["std", "env"] } +regex = "1.7.1" +serde = { version = "1.0.152", features = ["derive"] } +cookie = "0.16.2" futures-lite = "1.12.0" hyper = { version = "0.14.23", features = ["full"] } -hyper-rustls = "0.23.0" +hyper-rustls = "0.23.2" percent-encoding = "2.2.0" route-recognizer = "0.3.1" -serde_json = "1.0.87" -tokio = { version = "1.23.1", features = ["full"] } +serde_json = "1.0.91" +tokio = { version = "1.24.1", features = ["full"] } time = "0.3.17" url = "2.3.1" rust-embed = { version = "6.4.2", features = ["include-exclude"] } libflate = "1.2.0" brotli = { version = "3.3.4", features = ["std"] } -toml = "0.5.9" -once_cell = "1.16.0" +toml = "0.5.10" +once_cell = "1.17.0" [dev-dependencies] lipsum = "0.8.2" From 3d0287f04fb31068b96c19dc0020160586304efd Mon Sep 17 00:00:00 2001 From: Matthew Esposito Date: Mon, 16 Jan 2023 15:05:53 -0500 Subject: [PATCH 92/92] Add comment count in post (#659) * Add comment count in post * Restyle comment count --- static/style.css | 11 +++++++++++ templates/post.html | 1 + 2 files changed, 12 insertions(+) diff --git a/static/style.css b/static/style.css index 4981555..3ff48c4 100644 --- a/static/style.css +++ b/static/style.css @@ -849,6 +849,17 @@ a.search_subreddit:hover { font-weight: bold; } +#comment_count { + font-weight: 500; + opacity: 0.9; +} + +#comment_count > #sorted_by { + font-weight: normal; + opacity: 0.7; + margin-right: 7px; +} + #post_links { display: flex; list-style: none; diff --git a/templates/post.html b/templates/post.html index d69644b..c79a18d 100644 --- a/templates/post.html +++ b/templates/post.html @@ -44,6 +44,7 @@ +

{{post.comments.0}} {% if post.comments.0 == "1" %}comment{% else %}comments{% endif %} sorted by