Compare commits

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

250 commits

Author SHA1 Message Date
renovate[bot]
d58d3053be
fix(deps): update rust crate libwebp-sys to 0.12.0 (#280)
Some checks failed
Build using Cargo / build (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 08:24:41 +00:00
renovate[bot]
b04a2936ce
fix(deps): update rust crate listenfd to v1.0.2 (#278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 02:07:15 +00:00
renovate[bot]
f123351466
chore(deps): lock file maintenance (#279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 02:06:54 +00:00
renovate[bot]
2c0ab71e58
chore(deps): lock file maintenance (#277)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-13 00:28:40 +00:00
renovate[bot]
c911eaa78d
fix(deps): update rust crate tokio to v1.43.0 (#276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-08 17:58:43 +00:00
renovate[bot]
bba7f3957a
chore(deps): lock file maintenance (#274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-06 02:12:26 +00:00
renovate[bot]
ecec9d8aea
fix(deps): update rust crate reqwest to v0.12.12 (#273)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-31 19:41:05 +00:00
renovate[bot]
12d9972ce9
chore(deps): lock file maintenance (#272)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 02:26:21 +00:00
renovate[bot]
bf19e31d24
fix(deps): update rust crate reqwest to v0.12.11 (#271)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-27 16:03:56 +00:00
renovate[bot]
81cb1d6bc4
fix(deps): update rust crate reqwest to v0.12.10 (#270)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-26 18:36:33 +00:00
renovate[bot]
65084b2dee
chore(deps): lock file maintenance (#269)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 02:20:36 +00:00
renovate[bot]
279654bb29
chore(deps): lock file maintenance (#268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 00:23:19 +00:00
Kavin
47007b9ea2
Merge pull request #267 from unixfox/fix-expire-check
fix: wrong comparaison with expire time
2024-12-15 13:59:49 +05:30
Émilien (perso)
2562d701b0
fix: wrong comparaison with expire time 2024-12-14 18:29:43 +01:00
Kavin
ec006b3999
Check if expire time is in the past.
Closes #265
2024-12-14 18:34:08 +05:30
Kavin
feaceaa14b
Update to reqwest 0.12. 2024-12-14 18:24:30 +05:30
renovate[bot]
6855a9bb9e
chore(deps): lock file maintenance (#264)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 01:25:02 +00:00
renovate[bot]
7942450739
fix(deps): update rust crate tokio to v1.42.0 (#263)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 17:41:27 +00:00
renovate[bot]
a68ceed593
chore(deps): lock file maintenance (#262)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 01:18:23 +00:00
renovate[bot]
4d68fe4f68
fix(deps): update rust crate bytes to v1.9.0 (#261)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 13:17:48 +00:00
renovate[bot]
509a257fe4
fix(deps): update rust crate blake3 to v1.5.5 (#260)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 04:17:17 +00:00
renovate[bot]
2aa78a17b8
chore(deps): lock file maintenance (#259)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 01:34:58 +00:00
renovate[bot]
e1d10b02a2
chore(deps): lock file maintenance (#258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 01:01:02 +00:00
renovate[bot]
d6039c2313
chore(deps): lock file maintenance (#256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 01:12:27 +00:00
renovate[bot]
444d2ae7fb
fix(deps): update rust crate tokio to v1.41.1 (#255)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-07 14:39:39 +00:00
renovate[bot]
f5439bcd59 fix(deps): update rust crate image to v0.25.5 2024-11-05 12:53:17 +00:00
renovate[bot]
c19314084f chore(deps): lock file maintenance 2024-11-04 01:24:52 +00:00
renovate[bot]
af9bb595ad fix(deps): update rust crate libwebp-sys to 0.11.0 2024-10-29 06:16:23 +00:00
renovate[bot]
157e0307a8 chore(deps): lock file maintenance 2024-10-28 01:25:55 +00:00
renovate[bot]
5c1f32b311 fix(deps): update rust crate regex to v1.11.1 2024-10-24 15:42:42 +00:00
renovate[bot]
be3183a62e fix(deps): update rust crate tokio to v1.41.0 2024-10-22 10:05:00 +00:00
renovate[bot]
855d786435 fix(deps): update rust crate bytes to v1.8.0 2024-10-21 20:25:52 +00:00
renovate[bot]
35d3e66f9a chore(deps): lock file maintenance 2024-10-21 00:12:23 +00:00
renovate[bot]
5268e9093b fix(deps): update rust crate image to v0.25.4 2024-10-17 20:50:59 +00:00
renovate[bot]
df8889ad08 fix(deps): update rust crate ravif to v0.11.11 2024-10-17 20:50:35 +00:00
renovate[bot]
8585aa927c fix(deps): update rust crate image to v0.25.3 2024-10-16 18:52:13 +00:00
renovate[bot]
2df6913fc5 chore(deps): lock file maintenance 2024-10-14 01:00:02 +00:00
renovate[bot]
e8a46ba3bf chore(deps): lock file maintenance 2024-10-07 01:37:46 +00:00
renovate[bot]
23db56a0e1 fix(deps): update rust crate once_cell to v1.20.2 2024-10-05 18:23:49 +00:00
renovate[bot]
d43c517834 fix(deps): update rust crate futures-util to v0.3.31 2024-10-05 09:32:31 +00:00
renovate[bot]
7172ff43d3 chore(deps): lock file maintenance 2024-09-30 00:08:32 +00:00
renovate[bot]
2d5be4582b fix(deps): update rust crate regex to v1.11.0 2024-09-29 16:14:25 +00:00
renovate[bot]
81eb3650b6 fix(deps): update rust crate once_cell to v1.20.1 2024-09-29 16:13:31 +00:00
renovate[bot]
54438c9122 fix(deps): update rust crate libwebp-sys to v0.10.1 2024-09-24 10:12:51 +00:00
renovate[bot]
d0d97f282e chore(deps): lock file maintenance 2024-09-23 00:31:18 +00:00
renovate[bot]
f8388eef52 fix(deps): update rust crate bytes to v1.7.2 2024-09-18 07:16:50 +00:00
renovate[bot]
f6a6e59395 chore(deps): lock file maintenance 2024-09-16 01:16:25 +00:00
renovate[bot]
f6ffd3d8bb fix(deps): update rust crate libwebp-sys to 0.10.0 2024-09-10 13:33:53 +00:00
renovate[bot]
0f290ff3b6 chore(deps): lock file maintenance 2024-09-09 00:52:13 +00:00
renovate[bot]
e4ca4966e8 chore(deps): lock file maintenance 2024-09-02 03:26:48 +00:00
renovate[bot]
216dd46850 chore(deps): lock file maintenance 2024-09-02 01:48:32 +00:00
renovate[bot]
8f33ee95f6 chore(deps): lock file maintenance 2024-08-26 00:42:12 +00:00
renovate[bot]
79f27fbfc9 fix(deps): update rust crate blake3 to v1.5.4 2024-08-19 19:45:11 +00:00
renovate[bot]
77d84a6099 chore(deps): lock file maintenance 2024-08-19 01:26:34 +00:00
renovate[bot]
baaef0d1cb fix(deps): update rust crate tokio to v1.39.3 2024-08-17 18:27:03 +00:00
renovate[bot]
07e41e6b17 chore(deps): lock file maintenance 2024-08-12 01:58:40 +00:00
renovate[bot]
dce6ee7965 fix(deps): update rust crate actix-web to v4.9.0 2024-08-10 05:26:07 +00:00
renovate[bot]
c6f6ddb2d0 fix(deps): update rust crate ravif to v0.11.10 2024-08-08 11:53:37 +00:00
renovate[bot]
f8afab7746 fix(deps): update rust crate rgb to v0.8.48 2024-08-07 20:48:47 +00:00
renovate[bot]
86d0c5b342 chore(deps): lock file maintenance 2024-08-05 01:51:20 +00:00
renovate[bot]
b4e6bb0cf1 fix(deps): update rust crate rgb to v0.8.47 2024-08-04 19:47:51 +00:00
Kavin
e223e1e22e
Only do UMP handling on web client. 2024-08-02 17:48:01 +01:00
renovate[bot]
b0381834f6 fix(deps): update rust crate regex to v1.10.6 2024-08-02 16:37:34 +00:00
renovate[bot]
4c73d55fc7 fix(deps): update rust crate bytes to v1.7.1 2024-08-01 21:54:22 +00:00
renovate[bot]
9f590b05ef fix(deps): update rust crate bytes to v1.7.0 2024-07-31 12:05:45 +00:00
renovate[bot]
9ca4db8b60 chore(deps): lock file maintenance 2024-07-29 01:02:37 +00:00
renovate[bot]
5b16b6fd1a fix(deps): update rust crate tokio to v1.39.2 2024-07-27 11:04:31 +00:00
renovate[bot]
cdea5d459f fix(deps): update rust crate ravif to v0.11.9 2024-07-25 01:45:36 +00:00
renovate[bot]
bf23ac4150 fix(deps): update rust crate tokio to v1.39.1 2024-07-23 18:21:03 +00:00
renovate[bot]
1c41b946dc fix(deps): update rust crate tokio to v1.39.0 2024-07-23 15:01:08 +00:00
renovate[bot]
71a6cf186b chore(deps): lock file maintenance 2024-07-22 02:30:22 +00:00
renovate[bot]
98db4af9a2 fix(deps): update rust crate image to v0.25.2 2024-07-21 20:19:09 +00:00
renovate[bot]
944fa424ab fix(deps): update rust crate tokio to v1.38.1 2024-07-16 19:14:00 +00:00
renovate[bot]
bbe50947f3 fix(deps): update rust crate rgb to v0.8.45 2024-07-16 01:06:07 +00:00
renovate[bot]
a6b82581c9 fix(deps): update rust crate blake3 to v1.5.3 2024-07-15 07:26:49 +00:00
renovate[bot]
ff72521f0b chore(deps): lock file maintenance 2024-07-15 00:44:42 +00:00
renovate[bot]
91ad17aeb3 fix(deps): update rust crate bytes to v1.6.1 2024-07-13 11:56:24 +00:00
renovate[bot]
ccd8443143 fix(deps): update rust crate blake3 to v1.5.2 2024-07-12 18:38:01 +00:00
renovate[bot]
ea2088bbde fix(deps): update rust crate rgb to v0.8.44 2024-07-08 14:31:45 +00:00
renovate[bot]
efa007accf chore(deps): lock file maintenance 2024-07-08 01:09:07 +00:00
renovate[bot]
c301dfdc70 fix(deps): update rust crate ravif to v0.11.8 2024-07-07 21:24:18 +00:00
renovate[bot]
e018193bc8 fix(deps): update rust crate rgb to v0.8.42 2024-07-07 18:58:44 +00:00
renovate[bot]
7307d9521d chore(deps): lock file maintenance 2024-07-01 02:14:03 +00:00
renovate[bot]
e7931addf5 fix(deps): update rust crate rgb to v0.8.40 2024-06-28 16:12:15 +00:00
renovate[bot]
a3a13767cf chore(deps): lock file maintenance 2024-06-24 02:09:22 +00:00
renovate[bot]
05d0c63491 fix(deps): update rust crate mimalloc to v0.1.43 2024-06-23 16:04:23 +00:00
renovate[bot]
7da6cde3fd fix(deps): update rust crate actix-web to v4.8.0 2024-06-20 01:08:41 +00:00
Jeidnx
7deb4175e3 feat: Get listener from fd 2024-06-17 21:25:21 +02:00
renovate[bot]
c7ecef8c4b chore(deps): lock file maintenance 2024-06-17 01:13:08 +00:00
renovate[bot]
588a48c5ca fix(deps): update rust crate ravif to v0.11.7 2024-06-16 15:41:42 +00:00
renovate[bot]
841b545734 chore(deps): lock file maintenance 2024-06-10 00:39:29 +00:00
renovate[bot]
ee5639c556 fix(deps): update rust crate regex to v1.10.5 2024-06-09 13:19:32 +00:00
renovate[bot]
eac03af2ae fix(deps): update rust crate actix-web to v4.7.0 2024-06-09 00:36:05 +00:00
renovate[bot]
d1d1c0f0f2 chore(deps): lock file maintenance 2024-06-03 00:27:00 +00:00
renovate[bot]
aad4375921 fix(deps): update rust crate tokio to v1.38.0 2024-05-30 22:07:43 +00:00
renovate[bot]
f6b582487b chore(deps): lock file maintenance 2024-05-27 00:47:13 +00:00
renovate[bot]
d9c8306c31 fix(deps): update rust crate mimalloc to v0.1.42 2024-05-20 11:52:16 +00:00
renovate[bot]
4eff28432a fix(deps): update rust crate actix-web to v4.6.0 2024-05-19 16:37:53 +00:00
renovate[bot]
31b3d3bcfa chore(deps): lock file maintenance 2024-05-13 00:05:41 +00:00
Kavin
0daf0e77a4
Merge pull request #179 from TeamPiped/error-handling
refactor: simplify error handling
2024-05-12 21:42:34 +05:30
Bnyro
4026431403 refactor: move get_env_bool to utils.rs 2024-05-08 21:54:01 +02:00
Bnyro
3f8a33b9d6 refactor: simplify error handling 2024-05-08 21:53:57 +02:00
Bnyro
b92473d149
Merge pull request #178 from TeamPiped/fix-dearrow-crash
fix: LibreTube crashes when loading DeArrow thumbnails
2024-05-06 12:37:40 +02:00
Bnyro
7320cd0b22 fix: LibreTube crashes when loading DeArrow thumbnails 2024-05-06 12:32:58 +02:00
renovate[bot]
f0a5da9dcb chore(deps): lock file maintenance 2024-05-06 01:00:33 +00:00
renovate[bot]
25f56b8044 chore(deps): lock file maintenance 2024-04-29 01:46:20 +00:00
renovate[bot]
5367f9232f fix(deps): update rust crate mimalloc to 0.1.41 2024-04-22 20:27:51 +00:00
renovate[bot]
6c83daa58e chore(deps): lock file maintenance 2024-04-22 00:05:51 +00:00
renovate[bot]
88a29fd2c0 chore(deps): lock file maintenance 2024-04-15 00:16:05 +00:00
renovate[bot]
7543a4dff7 chore(deps): lock file maintenance 2024-04-08 01:21:25 +00:00
Bnyro
8e93dde1b5
Merge pull request #170 from TeamPiped/harden-headers
fix: filter out some headers that could leak user information
2024-04-05 20:20:57 +02:00
Bnyro
52896e779c
fix: filter out some headers that could leak user information 2024-04-05 20:17:44 +02:00
renovate[bot]
a872d9f7b6 chore(deps): lock file maintenance 2024-04-01 00:36:36 +00:00
renovate[bot]
69a296680e fix(deps): update rust crate image to 0.25.1 2024-03-31 03:06:40 +00:00
renovate[bot]
da2451e40e fix(deps): update rust crate tokio to 1.37.0 2024-03-28 19:07:37 +00:00
renovate[bot]
571fc36a52 chore(deps): lock file maintenance 2024-03-25 01:08:59 +00:00
renovate[bot]
9412262acb fix(deps): update rust crate regex to 1.10.4 2024-03-23 05:31:55 +00:00
renovate[bot]
2e27228ff5 fix(deps): update rust crate bytes to 1.6.0 2024-03-22 21:06:16 +00:00
renovate[bot]
300a15acec fix(deps): update rust crate reqwest to 0.11.27 2024-03-19 20:04:00 +00:00
renovate[bot]
42aa4b39e5 chore(deps): lock file maintenance 2024-03-18 02:12:38 +00:00
renovate[bot]
35de41cd87 fix(deps): update rust crate ravif to 0.11.5 2024-03-14 14:44:01 +00:00
renovate[bot]
5dc8fd3308 fix(deps): update rust crate reqwest to 0.11.26 2024-03-12 17:53:05 +00:00
renovate[bot]
ffb200a10f fix(deps): update rust crate blake3 to 1.5.1 2024-03-12 12:27:46 +00:00
Kavin
e8169726b4
Run clippy fix. 2024-03-11 09:10:10 +00:00
Kavin
407ee38e3a Update features for image crate. 2024-03-11 09:02:14 +00:00
renovate[bot]
3bf276a0ed fix(deps): update rust crate image to 0.25.0 2024-03-11 09:02:14 +00:00
renovate[bot]
9ede2496f1 chore(deps): lock file maintenance 2024-03-11 01:35:50 +00:00
renovate[bot]
d2513f125c fix(deps): update rust crate reqwest to 0.11.25 2024-03-09 01:48:44 +00:00
renovate[bot]
69ecdb8933 chore(deps): lock file maintenance 2024-03-04 00:29:05 +00:00
renovate[bot]
e13f7adef7 chore(deps): lock file maintenance 2024-02-26 01:48:27 +00:00
renovate[bot]
5e171bb47a fix(deps): update rust crate image to 0.24.9 2024-02-23 06:41:30 +00:00
renovate[bot]
db158b11a5 fix(deps): update rust crate libwebp-sys to 0.9.5 2024-02-19 06:49:54 +00:00
renovate[bot]
8e392ed2e3 chore(deps): lock file maintenance 2024-02-19 01:57:01 +00:00
renovate[bot]
28fd48b6a3 chore(deps): lock file maintenance 2024-02-12 00:37:29 +00:00
renovate[bot]
34e83cc2bf chore(deps): lock file maintenance 2024-02-05 01:36:21 +00:00
renovate[bot]
b6e950175a fix(deps): update rust crate actix-web to 4.5.1 2024-02-04 04:29:05 +00:00
renovate[bot]
9327f06390 fix(deps): update rust crate tokio to 1.36.0 2024-02-02 13:02:01 +00:00
renovate[bot]
1c58d60539 fix(deps): update rust crate reqwest to 0.11.24 2024-01-31 18:30:27 +00:00
renovate[bot]
1c12a67ed7 chore(deps): lock file maintenance 2024-01-29 01:57:36 +00:00
renovate[bot]
0098582abe chore(deps): lock file maintenance 2024-01-22 01:48:32 +00:00
renovate[bot]
e3ae57420c fix(deps): update rust crate regex to 1.10.3 2024-01-21 15:32:44 +00:00
renovate[bot]
97c9282197 chore(deps): lock file maintenance 2024-01-15 00:11:36 +00:00
renovate[bot]
17c453e51b fix(deps): update rust crate image to 0.24.8 2024-01-13 22:50:29 +00:00
renovate[bot]
ffe1cf5b48 fix(deps): update rust crate ravif to 0.11.4 2024-01-08 20:02:20 +00:00
renovate[bot]
f29b2ae68d chore(deps): lock file maintenance 2024-01-08 02:00:56 +00:00
Kavin
e0bb6a3a78
Only attempt ump decoding when response is successful. 2024-01-03 18:25:30 +00:00
renovate[bot]
000a14e738 chore(deps): update ilammy/setup-nasm action to v1.5.1 2024-01-01 11:45:24 +00:00
renovate[bot]
37d32493dd chore(deps): lock file maintenance 2024-01-01 00:27:43 +00:00
renovate[bot]
7448e18b77 chore(deps): lock file maintenance 2023-12-25 01:18:50 +00:00
renovate[bot]
4b4a67a3b4 fix(deps): update rust crate actix-web to 4.4.1 2023-12-24 18:27:49 +00:00
renovate[bot]
1ce21d827e fix(deps): update rust crate futures-util to 0.3.30 2023-12-24 16:59:49 +00:00
renovate[bot]
2c41c17c36 fix(deps): update rust crate tokio to 1.35.1 2023-12-19 18:29:50 +00:00
renovate[bot]
0338e8b68f chore(deps): lock file maintenance 2023-12-18 21:30:41 +00:00
renovate[bot]
c0ac30e886 fix(deps): update rust crate reqwest to 0.11.23 2023-12-18 21:30:17 +00:00
renovate[bot]
d72b2c421c chore(deps): lock file maintenance 2023-12-18 00:38:40 +00:00
Kavin
cd8cf245c0
Set content-length and range query parameter properly. 2023-12-15 17:57:46 +00:00
Kavin
7c72df8f0d
Add error logging for UMP Transforming Errors in the transformed stream 2023-12-14 22:48:39 +00:00
Kavin
437ee17508
Poll should be pending when there's not enough data to read. 2023-12-14 22:19:13 +00:00
renovate[bot]
1dbe891119 chore(deps): update actions/upload-artifact action to v4 2023-12-14 20:15:36 +00:00
Kavin
e291ed4e19
Refactor utils and UMP transforming code to new files. 2023-12-14 13:37:52 +00:00
Kavin
e90eebcbd7
Don't include /range/ in hash
See https://github.com/TeamPiped/Piped/issues/3211
2023-12-14 05:03:55 +00:00
Kavin
19dca8bdd0
Escape URL when rewriting DASH responses. 2023-12-14 05:03:08 +00:00
Kavin
7586ae314b
Refactor UmpTransformStream to use io::Error instead of ReqwestError
- Replaced all occurrences of `ReqwestError` with `io::Error` in the code.
- Updated the type signature and implementation of `UmpTransformStream` to use `io::Error`.
- Handled errors when calling `read_variable_integer` by returning an error result.
2023-12-11 22:51:16 +00:00
renovate[bot]
e158c3aef8 chore(deps): lock file maintenance 2023-12-11 03:32:18 +00:00
renovate[bot]
961ae28fc2 chore(deps): lock file maintenance 2023-12-11 01:11:28 +00:00
renovate[bot]
a2717e3cb3 fix(deps): update rust crate tokio to 1.35.0 2023-12-09 00:34:44 +00:00
Kavin
c3b78def59
Be compliant with rfc7233 for sending a 206 response. 2023-12-08 10:47:52 +00:00
renovate[bot]
118c005d4d fix(deps): update rust crate once_cell to 1.19.0 2023-12-07 13:49:05 +00:00
Kavin
a9bc07e98d
Send 206 response in UMP response content. 2023-12-06 06:39:18 +00:00
renovate[bot]
b9c8dc8f58 chore(deps): lock file maintenance 2023-12-04 01:34:58 +00:00
Kavin
2295ad3d94
Add range header handling for ump streams.
See https://github.com/TeamPiped/Piped/issues/3196
2023-11-30 02:10:50 +00:00
Kavin
75f7c4e8cd
Return the right variable when rewriting manifests
This should now correctly return the rewritten manifest.
2023-11-28 18:36:36 +00:00
Kavin
a2e77d2668
Fix for another edge case. 2023-11-28 03:47:04 +00:00
Kavin
3e8098d105
Fix issues with skipping certain stream segments. 2023-11-28 02:54:02 +00:00
Kavin
67a519978b
Merge pull request #120 from TeamPiped/ump-support
Add support for handling ump responses
2023-11-27 23:58:37 +00:00
Kavin
2164f907ef
Add support for handling ump responses. 2023-11-27 23:54:55 +00:00
renovate[bot]
cc5337325d chore(deps): lock file maintenance 2023-11-27 02:12:54 +00:00
Kavin
496f58f81a
fix: Add support for generating qhash in rewritten manifests
Closes https://github.com/TeamPiped/Piped/issues/3162
2023-11-21 12:45:53 +00:00
Kavin
d72fb3c445
Include path in hash 2023-11-20 08:32:37 +00:00
Kavin
01697ebb86
Filter qhash query parameter. 2023-11-20 08:09:38 +00:00
Kavin
dfe87e0292
Fix clippy issue. 2023-11-20 08:05:47 +00:00
Kavin
0a6feb88ae
Merge pull request #116 from TeamPiped/blake3-query-hashing
Implement blake3 cryptographic hash verification for query string
2023-11-20 05:24:46 +00:00
Kavin
2aa3053d34
Remove use of channel. 2023-11-20 05:21:46 +00:00
Kavin
830363ca64
Remove rayon feature. 2023-11-20 05:14:26 +00:00
Kavin
2abd43bfb2
Make the hashing run on spawn_blocking. 2023-11-20 05:13:31 +00:00
Kavin
faafbcb737
Implement blake3 cryptographic hash verification for query string. 2023-11-20 05:13:31 +00:00
renovate[bot]
c136f79cc2 chore(deps): lock file maintenance 2023-11-20 02:06:30 +00:00
Kavin
04e383557d
Merge pull request #117 from RealOrangeOne/native-spawn-blocking-return
Let `spawn_blocking` handle returning its own value
2023-11-18 17:34:59 +00:00
Jake Howard
031df8da4d
Let spawn_blocking handle returning its own value
This means one fewer thing to await on, and spin up inside a request. It _might_ be faster, who knows, but it can't hurt.
2023-11-18 16:32:28 +00:00
renovate[bot]
9cda613cd2 chore(deps): lock file maintenance 2023-11-13 00:14:57 +00:00
renovate[bot]
c445f844bc fix(deps): update rust crate tokio to 1.34.0 2023-11-09 22:59:43 +00:00
renovate[bot]
b2bde77221 chore(deps): lock file maintenance 2023-11-06 03:45:24 +00:00
renovate[bot]
8f65ae0f88 chore(deps): lock file maintenance 2023-11-06 01:39:46 +00:00
Kavin
fffe690964
Add SIMD optimization feature flag. 2023-10-30 23:52:21 +00:00
renovate[bot]
f3a4092f5c chore(deps): lock file maintenance 2023-10-30 02:04:32 +00:00
renovate[bot]
b36d114dc3 fix(deps): update rust crate rgb to 0.8.37 2023-10-29 12:59:05 +00:00
renovate[bot]
03adf97fb3 chore(deps): lock file maintenance 2023-10-23 02:08:13 +00:00
Bnyro
63e5d77636
Merge pull request #30 from Jeidnx/check_env
Actually check boolean env vars
2023-10-20 16:18:40 +02:00
Bnyro
151b10775f refactor: properly check boolean env vars
Co-authored-by: Jeidnx <jeidnx@domainhier.de>
2023-10-20 16:14:35 +02:00
renovate[bot]
07d35aa4b2 fix(deps): update rust crate regex to 1.10.2 2023-10-16 17:30:04 +00:00
renovate[bot]
d17f56645b chore(deps): lock file maintenance 2023-10-16 02:01:00 +00:00
renovate[bot]
e166248424 fix(deps): update rust crate regex to 1.10.1 2023-10-14 16:29:19 +00:00
Kavin
bd9232d6c2
Small change and cargo fmt. 2023-10-10 02:08:05 +01:00
renovate[bot]
4472a17049 fix(deps): update rust crate regex to 1.10.0 2023-10-09 22:16:12 +00:00
renovate[bot]
c73e69310a fix(deps): update rust crate tokio to 1.33.0 2023-10-09 11:45:55 +00:00
renovate[bot]
f9c33f4edf chore(deps): lock file maintenance 2023-10-09 01:03:27 +00:00
renovate[bot]
510d8879d9 fix(deps): update rust crate reqwest to 0.11.22 2023-10-03 16:12:33 +00:00
renovate[bot]
9e3a9e9dab fix(deps): update rust crate reqwest to 0.11.21 2023-10-02 19:18:48 +00:00
renovate[bot]
cf487f6a0e chore(deps): lock file maintenance 2023-10-02 01:38:13 +00:00
renovate[bot]
1b86373072 fix(deps): update rust crate regex to 1.9.6 2023-09-30 14:02:49 +00:00
Kavin
57bac7177c
Fix compile issues. 2023-09-29 22:29:26 +01:00
Kavin
59eb2a1db8
Small code improvements. 2023-09-29 13:10:48 +01:00
Kavin
899997a1ec
Merge pull request #90 from chaoticryptidz/minimal-cargo-tidy
Allow more minimal cargo features & allow setting UDS filename
2023-09-29 13:05:50 +01:00
Kavin
0edb727a03
Small code improvement, 2023-09-29 13:00:59 +01:00
Kavin
3d99bdd454
Fix image transcoding check. 2023-09-29 13:00:33 +01:00
chaos
30c0926f2e
change default features for image to only build support for jpeg/webp decode as served by youtube and checked before decoding 2023-09-27 22:44:45 +01:00
chaos
70a167d34a
re-add compatibility with only UDS set 2023-09-27 21:41:09 +01:00
chaos
bf95377e9a
chore(deps): lock file maintenance 2023-09-27 21:41:09 +01:00
renovate[bot]
ba4a01dab4
fix(deps): update rust crate ravif to 0.11.3 2023-09-27 21:41:09 +01:00
chaos
7789af5658
Reformat code 2023-09-27 21:40:54 +01:00
chaos
f3754b46cf
Allow more minimal cargo features, tidy code, allow setting unix domain socket filename 2023-09-27 21:40:47 +01:00
renovate[bot]
884df6a08e chore(deps): lock file maintenance 2023-09-25 02:07:28 +00:00
Kavin
43c89f5406
actions: pin actions/checkout to v4 2023-09-22 19:42:39 +00:00
renovate[bot]
f0c58cf96b chore(deps): update actions/checkout digest to 8ade135 2023-09-22 19:36:09 +00:00
renovate[bot]
88cd1e968c fix(deps): update rust crate ravif to 0.11.3 2023-09-22 01:18:06 +00:00
renovate[bot]
fc9a0c5128 fix(deps): update rust crate libwebp-sys to 0.9.4 2023-09-18 08:24:34 +00:00
renovate[bot]
1ecc42d212 chore(deps): lock file maintenance 2023-09-18 03:35:59 +00:00
renovate[bot]
bc8bcb96a8 chore(deps): lock file maintenance 2023-09-18 02:19:09 +00:00
renovate[bot]
8201db45e5 fix(deps): update rust crate mimalloc to 0.1.39 2023-09-14 14:52:57 +00:00
renovate[bot]
8a3f8b26bd fix(deps): update rust crate libwebp-sys to 0.9.3 2023-09-13 07:47:28 +00:00
renovate[bot]
60fc664f2b chore(deps): lock file maintenance 2023-09-11 00:21:51 +00:00
Kavin
0d4eda637d
Perform webp and avif conversion on blocking tasks. 2023-09-09 05:13:30 +01:00
renovate[bot]
e642b968a8 chore(deps): update actions/checkout action to v4 2023-09-04 20:16:56 +00:00
renovate[bot]
03e7d8354a chore(deps): lock file maintenance 2023-09-04 01:20:30 +00:00
renovate[bot]
d5f1176639 fix(deps): update rust crate regex to 1.9.5 2023-09-02 19:47:31 +00:00
renovate[bot]
b6bde9e31a fix(deps): update rust crate actix-web to 4.4.0 2023-08-29 05:10:48 +00:00
renovate[bot]
cff48975f3 chore(deps): lock file maintenance 2023-08-28 01:23:04 +00:00
Kavin
e1d963c855
Make a static binary. 2023-08-27 18:32:58 +01:00
Kavin
02b40729cb
Use the mold linker. 2023-08-27 18:32:30 +01:00
Kavin
75d9fa9a30
Upload piped-proxy artifact. 2023-08-27 18:14:47 +01:00
renovate[bot]
39d2c29365 fix(deps): update rust crate regex to 1.9.4 2023-08-26 14:30:01 +00:00
renovate[bot]
338190876f fix(deps): update rust crate mimalloc to 0.1.38 2023-08-25 13:13:24 +00:00
renovate[bot]
ced5852805 fix(deps): update rust crate reqwest to 0.11.20 2023-08-23 22:33:13 +00:00
Kavin
ef6250ba72
Fix compile issues. 2023-08-21 23:03:00 +01:00
Kavin
63953d283e
Add support for using proxies. 2023-08-21 22:56:18 +01:00
renovate[bot]
ab32f6a140 fix(deps): update rust crate reqwest to 0.11.19 2023-08-21 21:45:56 +00:00
renovate[bot]
03ad68ba13 chore(deps): lock file maintenance 2023-08-21 02:03:19 +00:00
renovate[bot]
fe8fef85c6 fix(deps): update rust crate tokio to 1.32.0 2023-08-17 00:40:25 +00:00
renovate[bot]
0a17c1fcad chore(deps): lock file maintenance 2023-08-14 00:44:51 +00:00
renovate[bot]
35c075ca08 fix(deps): update rust crate tokio to 1.31.0 2023-08-12 18:35:25 +00:00
7 changed files with 1924 additions and 1318 deletions

View file

@ -14,9 +14,16 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- uses: rui314/setup-mold@v1
- name: Set up NASM
uses: ilammy/setup-nasm@v1.4.0
uses: ilammy/setup-nasm@v1.5.1
- name: Build
run: cargo build --release
run: RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-gnu
- run: mv target/x86_64-unknown-linux-gnu/release/piped-proxy piped-proxy
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: piped-proxy
path: piped-proxy

View file

@ -4,7 +4,7 @@ jobs:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install clippy
uses: dtolnay/rust-toolchain@stable
with:

2426
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,22 +6,43 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "4.3.1"
image = "0.24.7"
libwebp-sys = { version = "0.9.2", optional = true }
mimalloc = "0.1.37"
once_cell = "1.18.0"
# Web Requests & Async Runtime
tokio = { version = "1.37.0", features = ["full"] }
actix-web = "4.5.1"
reqwest = { version = "0.12.9", features = ["stream", "brotli", "gzip", "socks"], default-features = false }
qstring = "0.7.2"
ravif = { version = "0.11.2", optional = true }
rgb = { version = "0.8.36", optional = true }
regex = "1.9.3"
reqwest = { version = "0.11.18", features = ["rustls-tls", "stream", "brotli", "gzip"], default-features = false }
tokio = { version = "1.30.0", features = ["full"] }
# Alternate Allocator
mimalloc = { version = "0.1.41", optional = true }
# Transcoding Images to WebP/AVIF to save bandwidth
image = { version = "0.25.1", features = ["jpeg", "webp", "rayon"], default-features = false, optional = true }
libwebp-sys = { version = "0.12.0", optional = true }
ravif = { version = "0.11.5", optional = true }
rgb = { version = "0.8.37", optional = true }
once_cell = "1.19.0"
regex = "1.10.4"
blake3 = { version = "1.5.5", optional = true }
bytes = "1.9.0"
futures-util = "0.3.30"
listenfd = "1.0.1"
http = "1.2.0"
[features]
default = ["webp"]
avif = ["dep:ravif", "dep:rgb"]
webp = ["dep:libwebp-sys"]
default = ["webp", "mimalloc", "reqwest-rustls", "qhash"]
reqwest-rustls = ["reqwest/rustls-tls"]
reqwest-native-tls = ["reqwest/default-tls"]
avif = ["dep:ravif", "dep:rgb", "dep:image"]
webp = ["dep:libwebp-sys", "dep:image"]
mimalloc = ["dep:mimalloc"]
optimized = ["libwebp-sys?/sse41", "libwebp-sys?/avx2", "libwebp-sys?/neon"]
qhash = ["blake3"]
[profile.release]
lto = true

View file

@ -1,34 +1,97 @@
use std::env;
use std::error::Error;
mod ump_stream;
mod utils;
use actix_web::{App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, web};
use actix_web::http::Method;
use mimalloc::MiMalloc;
use actix_web::http::StatusCode;
use actix_web::{web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer};
use listenfd::ListenFd;
use once_cell::sync::Lazy;
use qstring::QString;
use regex::Regex;
use reqwest::{Body, Client, Request, Url};
use std::error::Error;
use std::io::ErrorKind;
use std::net::TcpListener;
use std::os::unix::net::UnixListener;
use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, io};
#[cfg(not(any(feature = "reqwest-native-tls", feature = "reqwest-rustls")))]
compile_error!("feature \"reqwest-native-tls\" or \"reqwest-rustls\" must be set for proxy to have TLS support");
use futures_util::TryStreamExt;
use http::{HeaderName, Method};
use reqwest::header::HeaderValue;
#[cfg(any(feature = "webp", feature = "avif", feature = "qhash"))]
use tokio::task::spawn_blocking;
use ump_stream::UmpTransformStream;
#[cfg(feature = "mimalloc")]
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
fn try_get_fd_listeners() -> (Option<UnixListener>, Option<TcpListener>) {
let mut fd = ListenFd::from_env();
let unix_listener = env::var("FD_UNIX").ok().map(|fd_unix| {
let fd_pos = fd_unix.parse().expect("FD_UNIX is not a number");
println!("Trying to take Unix socket at position {}", fd_pos);
fd.take_unix_listener(fd_pos)
.expect(format!("fd {} is not a Unix socket", fd_pos).as_str())
.expect(format!("fd {} has already been used", fd_pos).as_str())
});
let tcp_listener = env::var("FD_TCP").ok().map(|fd_tcp| {
let fd_pos = fd_tcp.parse().expect("FD_TCP is not a number");
println!("Trying to take TCP listener at position {}", fd_pos);
fd.take_tcp_listener(fd_pos)
.expect(format!("fd {} is not a TCP listener", fd_pos).as_str())
.expect(format!("fd {} has already been used", fd_pos).as_str())
});
(unix_listener, tcp_listener)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Running server!");
let server = HttpServer::new(|| {
let mut server = HttpServer::new(|| {
// match all requests
App::new().default_service(web::to(index))
});
// get port from env
if env::var("UDS").is_ok() {
server.bind_uds("./socket/actix.sock")?
let fd_listeners = try_get_fd_listeners();
if let Some(unix_listener) = fd_listeners.0 {
server = server
.listen_uds(unix_listener)
.expect("Error while trying to listen on Unix socket passed by fd");
println!("Listening on Unix socket passed by fd.");
}
if let Some(tcp_listener) = fd_listeners.1 {
server = server
.listen(tcp_listener)
.expect("Error while trying to listen on TCP listener passed by fd");
println!("Listening on TCP listener passed by fd.");
}
// Only bind manually if there is not already a listener
if server.addrs().is_empty() {
// get socket/port from env
// backwards compat when only UDS is set
server = if utils::get_env_bool("UDS") {
let socket_path =
env::var("BIND_UNIX").unwrap_or_else(|_| "./socket/actix.sock".to_string());
server.bind_uds(socket_path)?
} else {
let bind = env::var("BIND").unwrap_or_else(|_| "0.0.0.0:8080".to_string());
server.bind(bind)?
};
}
.run()
.await
server.run().await
}
static RE_DOMAIN: Lazy<Regex> =
@ -41,14 +104,31 @@ static CLIENT: Lazy<Client> = Lazy::new(|| {
let builder = Client::builder()
.user_agent("Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0");
if env::var("IPV4_ONLY").is_ok() {
let proxy = if let Ok(proxy) = env::var("PROXY") {
reqwest::Proxy::all(proxy).ok()
} else {
None
};
let builder = if let Some(proxy) = proxy {
// proxy basic auth
if let Ok(proxy_auth_user) = env::var("PROXY_USER") {
let proxy_auth_pass = env::var("PROXY_PASS").unwrap_or_default();
builder.proxy(proxy.basic_auth(&proxy_auth_user, &proxy_auth_pass))
} else {
builder.proxy(proxy)
}
} else {
builder
.local_address(Some("0.0.0.0".parse().unwrap()))
};
if utils::get_env_bool("IPV4_ONLY") {
builder.local_address("0.0.0.0".parse().ok())
} else {
builder
}
.build()
.unwrap()
} else {
builder.build().unwrap()
}
});
const ANDROID_USER_AGENT: &str = "com.google.android.youtube/1537338816 (Linux; U; Android 13; en_US; ; Build/TQ2A.230505.002; Cronet/113.0.5672.24)";
@ -86,56 +166,180 @@ fn is_header_allowed(header: &str) -> bool {
| "report-to"
| "strict-transport-security"
| "user-agent"
| "range"
| "transfer-encoding"
| "x-real-ip"
| "origin"
| "referer"
// the 'x-title' header contains non-ascii characters which is not allowed on some HTTP clients
| "x-title"
)
}
async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
if req.method() == Method::OPTIONS {
if req.method() == actix_web::http::Method::OPTIONS {
let mut response = HttpResponse::Ok();
add_headers(&mut response);
return Ok(response.finish());
} else if req.method() != Method::GET && req.method() != Method::HEAD {
} else if req.method() != actix_web::http::Method::GET
&& req.method() != actix_web::http::Method::HEAD
{
let mut response = HttpResponse::MethodNotAllowed();
add_headers(&mut response);
return Ok(response.finish());
}
// parse query string
let query = QString::from(req.query_string());
let mut query = QString::from(req.query_string());
let res = query.get("host");
let res = res.map(|s| s.to_string());
#[cfg(feature = "qhash")]
{
use std::collections::BTreeSet;
if res.is_none() {
return Err("No host provided".into());
let secret = env::var("HASH_SECRET");
if let Ok(secret) = secret {
let Some(qhash) = query.get("qhash") else {
return Err("No qhash provided".into());
};
if qhash.len() != 8 {
return Err("Invalid qhash provided".into());
}
let path = req.path().as_bytes().to_owned();
// Store sorted key-value pairs
let mut set = BTreeSet::new();
{
let pairs = query.to_pairs();
for (key, value) in &pairs {
if matches!(*key, "qhash" | "range" | "rewrite") {
continue;
}
set.insert((key.as_bytes().to_owned(), value.as_bytes().to_owned()));
}
}
let hash = spawn_blocking(move || {
let mut hasher = blake3::Hasher::new();
for (key, value) in set {
hasher.update(&key);
hasher.update(&value);
}
let range_marker = b"/range/";
// Find the slice before "/range/"
if let Some(position) = path
.windows(range_marker.len())
.position(|window| window == range_marker)
{
// Update the hasher with the part of the path before "/range/"
// We add +1 to include the "/" in the hash
// This is done for DASH streams for the manifests provided by YouTube
hasher.update(&path[..(position + 1)]);
} else {
hasher.update(&path);
}
hasher.update(secret.as_bytes());
let hash = hasher.finalize().to_hex();
hash[..8].to_owned()
})
.await
.unwrap();
if hash != qhash {
return Err("Invalid qhash provided".into());
}
}
}
let Some(host) = query.get("host").map(|s| s.to_string()) else {
return Err("No host provided".into());
};
#[cfg(any(feature = "webp", feature = "avif"))]
let disallow_image_transcoding = utils::get_env_bool("DISALLOW_IMAGE_TRANSCODING");
let rewrite = query.get("rewrite") != Some("false");
#[cfg(feature = "avif")]
let avif = query.get("avif") == Some("true");
let host = res.unwrap();
let domain = RE_DOMAIN.captures(host.as_str());
if domain.is_none() {
let Some(domain) = RE_DOMAIN
.captures(host.as_str())
.map(|domain| domain.get(1).unwrap().as_str())
else {
return Err("Invalid host provided".into());
}
let domain = domain.unwrap().get(1).unwrap().as_str();
};
if !ALLOWED_DOMAINS.contains(&domain) {
return Err("Domain not allowed".into());
}
let video_playback = req.path().eq("/videoplayback");
if video_playback {
if let Some(expiry) = query.get("expire") {
let expiry = expiry.parse::<i64>()?;
let now = SystemTime::now();
let now = now.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs() as i64;
if now > expiry {
return Err("Expire time in past".into());
}
}
}
let is_android = video_playback && query.get("c").unwrap_or("").eq("ANDROID");
let is_web = video_playback && query.get("c").unwrap_or("").eq("WEB");
let is_ump = video_playback && query.get("ump").is_some();
let mime_type = query.get("mime").map(|s| s.to_string());
let clen = query
.get("clen")
.map(|s| s.to_string().parse::<u64>().unwrap());
if video_playback && !query.has("range") {
if let Some(range) = req.headers().get("range") {
let range = range.to_str().unwrap();
let range = range.replace("bytes=", "");
let range = range.split('-').collect::<Vec<_>>();
let start = range[0].parse::<u64>().unwrap();
let end = match range[1].parse::<u64>() {
Ok(end) => end,
Err(_) => {
if let Some(clen) = clen {
clen - 1
} else {
0
}
}
};
if end != 0 {
let range = format!("{}-{}", start, end);
query.add_pair(("range", range));
}
} else if let Some(clen) = clen {
let range = format!("0-{}", clen - 1);
query.add_pair(("range", range));
}
}
let range = query.get("range").map(|s| s.to_string());
let qs = {
let collected = query
.into_pairs()
.into_iter()
.filter(|(key, _)| key != "host" && key != "rewrite")
.filter(|(key, _)| !matches!(key.as_str(), "host" | "rewrite" | "qhash"))
.collect::<Vec<_>>();
QString::new(collected)
};
@ -144,40 +348,38 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
url.set_query(Some(qs.to_string().as_str()));
let method = {
if !is_android && video_playback {
if is_web && video_playback {
Method::POST
} else {
req.method().clone()
Method::from_str(req.method().as_str())?
}
};
let mut request = Request::new(method, url);
if !is_android && video_playback {
if is_web && video_playback {
request.body_mut().replace(Body::from("x\0"));
}
let request_headers = request.headers_mut();
for (key, value) in req.headers() {
if is_header_allowed(key.as_str()) {
request_headers.insert(key, value.clone());
let key = key.as_str();
if is_header_allowed(key) {
request_headers.insert(
HeaderName::from_str(key)?,
HeaderValue::from_bytes(value.as_bytes())?,
);
}
}
if is_android {
request_headers.insert("User-Agent", ANDROID_USER_AGENT.parse().unwrap());
request_headers.insert("User-Agent", ANDROID_USER_AGENT.parse()?);
}
let resp = CLIENT.execute(request).await;
let resp = CLIENT.execute(request).await?;
if resp.is_err() {
return Err(resp.err().unwrap().into());
}
let resp = resp?;
let mut response = HttpResponse::build(resp.status());
let mut response = HttpResponse::build(StatusCode::from_u16(resp.status().as_u16())?);
add_headers(&mut response);
@ -190,12 +392,14 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
if rewrite {
if let Some(content_type) = resp.headers().get("content-type") {
#[cfg(feature = "avif")]
if content_type == "image/webp" || content_type == "image/jpeg" && avif {
if !disallow_image_transcoding
&& (content_type == "image/webp" || content_type == "image/jpeg" && avif)
{
let resp_bytes = resp.bytes().await.unwrap();
let (body, content_type) = spawn_blocking(|| {
use ravif::{Encoder, Img};
use rgb::FromSlice;
let resp_bytes = resp.bytes().await.unwrap();
let image = image::load_from_memory(&resp_bytes).unwrap();
let width = image.width() as usize;
@ -211,20 +415,23 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
.with_speed(7)
.encode_rgb(buffer);
return if let Ok(res) = res {
response.content_type("image/avif");
Ok(response.body(res.avif_file.to_vec()))
if let Ok(res) = res {
(res.avif_file.to_vec(), "image/avif")
} else {
response.content_type("image/jpeg");
Ok(response.body(resp_bytes))
};
(resp_bytes.into(), "image/jpeg")
}
})
.await
.unwrap();
response.content_type(content_type);
return Ok(response.body(body));
}
#[cfg(feature = "webp")]
if content_type == "image/jpeg" {
use libwebp_sys::{WebPEncodeRGB, WebPFree};
if !disallow_image_transcoding && content_type == "image/jpeg" {
let resp_bytes = resp.bytes().await.unwrap();
let (body, content_type) = spawn_blocking(|| {
use libwebp_sys::{WebPEncodeRGB, WebPFree};
let image = image::load_from_memory(&resp_bytes).unwrap();
let width = image.width();
@ -251,12 +458,15 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
};
if bytes.len() < resp_bytes.len() {
response.content_type("image/webp");
return Ok(response.body(bytes));
(bytes, "image/webp")
} else {
(resp_bytes.into(), "image/jpeg")
}
response.content_type("image/jpeg");
return Ok(response.body(resp_bytes));
})
.await
.unwrap();
response.content_type(content_type);
return Ok(response.body(body));
}
if content_type == "application/x-mpegurl"
@ -271,11 +481,13 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
if let Some(captures) = captures {
let url = captures.get(1).unwrap().as_str();
if url.starts_with("https://") {
return line
.replace(url, localize_url(url, host.as_str()).as_str());
return line.replace(
url,
utils::localize_url(url, host.as_str()).as_str(),
);
}
}
localize_url(line, host.as_str())
utils::localize_url(line, host.as_str())
})
.collect::<Vec<String>>()
.join("\n");
@ -283,43 +495,64 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, Box<dyn Error>> {
return Ok(response.body(modified));
}
if content_type == "video/vnd.mpeg.dash.mpd" || content_type == "application/dash+xml" {
let mut resp_str = resp.text().await.unwrap();
let clone_resp = resp_str.clone();
let captures = RE_DASH_MANIFEST.captures_iter(&clone_resp);
let resp_str = resp.text().await.unwrap();
let mut new_resp = resp_str.clone();
let captures = RE_DASH_MANIFEST.captures_iter(&resp_str);
for capture in captures {
let url = capture.get(1).unwrap().as_str();
let new_url = localize_url(url, host.as_str());
resp_str = resp_str.replace(url, new_url.as_str());
let new_url = utils::localize_url(url, host.as_str());
let new_url = utils::escape_xml(new_url.as_str());
new_resp = new_resp.replace(url, new_url.as_ref());
}
return Ok(response.body(resp_str));
return Ok(response.body(new_resp));
}
}
}
if let Some(content_length) = resp.headers().get("content-length") {
response.append_header(("content-length", content_length));
response.no_chunking(content_length.to_str().unwrap().parse::<u64>().unwrap());
}
if is_ump && resp.status().is_success() {
if let Some(mime_type) = mime_type {
response.content_type(mime_type);
}
if req.headers().contains_key("range") {
// check if it's not the whole stream
if let Some(ref range) = range {
if let Some(clen) = clen {
if range != &format!("0-{}", clen - 1) {
response.status(StatusCode::PARTIAL_CONTENT);
}
}
}
}
let resp = resp.bytes_stream();
let resp = resp.map_err(|e| io::Error::new(ErrorKind::Other, e));
let transformed_stream = UmpTransformStream::new(resp);
// print errors
let transformed_stream = transformed_stream.map_err(|e| {
eprintln!("UMP Transforming Error: {}", e);
e
});
// calculate content length from clen and range
if let Some(clen) = clen {
let length = if let Some(ref range) = range {
let range = range.replace("bytes=", "");
let range = range.split('-').collect::<Vec<_>>();
let start = range[0].parse::<u64>().unwrap();
let end = range[1].parse::<u64>().unwrap_or(clen - 1);
end - start + 1
} else {
clen
};
response.no_chunking(length);
}
return Ok(response.streaming(transformed_stream));
}
// Stream response
Ok(response.streaming(resp.bytes_stream()))
}
fn localize_url(url: &str, host: &str) -> String {
if url.starts_with("https://") {
let mut url = Url::parse(url).unwrap();
let host = url.host().unwrap().to_string();
// set host query param
url.query_pairs_mut().append_pair("host", &host);
return format!("{}?{}", url.path(), url.query().unwrap());
} else if url.ends_with(".m3u8") || url.ends_with(".ts") {
return if url.contains('?') {
format!("{}&host={}", url, host)
} else {
format!("{}?host={}", url, host)
};
}
url.to_string()
}

154
src/ump_stream.rs Normal file
View file

@ -0,0 +1,154 @@
use crate::utils;
use bytes::{Bytes, BytesMut};
use futures_util::Stream;
use std::io;
use std::io::ErrorKind;
use std::pin::Pin;
use std::task::{Context, Poll};
fn read_variable_integer(buf: &[u8], offset: usize) -> io::Result<(i32, usize)> {
let mut pos = offset;
let prefix = utils::read_buf(buf, &mut pos);
let mut size = 0;
for shift in 1..=5 {
if prefix & (128 >> (shift - 1)) == 0 {
size = shift;
break;
}
}
if !(1..=5).contains(&size) {
return Err(io::Error::new(
ErrorKind::InvalidData,
format!("Invalid integer size {} at position {}", size, offset),
));
}
match size {
1 => Ok((prefix as i32, size)),
2 => {
let value = ((utils::read_buf(buf, &mut pos) as i32) << 6) | (prefix as i32 & 0b111111);
Ok((value, size))
}
3 => {
let value = (((utils::read_buf(buf, &mut pos) as i32)
| ((utils::read_buf(buf, &mut pos) as i32) << 8))
<< 5)
| (prefix as i32 & 0b11111);
Ok((value, size))
}
4 => {
let value = (((utils::read_buf(buf, &mut pos) as i32)
| ((utils::read_buf(buf, &mut pos) as i32) << 8)
| ((utils::read_buf(buf, &mut pos) as i32) << 16))
<< 4)
| (prefix as i32 & 0b1111);
Ok((value, size))
}
_ => {
let value = (utils::read_buf(buf, &mut pos) as i32)
| ((utils::read_buf(buf, &mut pos) as i32) << 8)
| ((utils::read_buf(buf, &mut pos) as i32) << 16)
| ((utils::read_buf(buf, &mut pos) as i32) << 24);
Ok((value, size))
}
}
}
pub struct UmpTransformStream<S>
where
S: Stream<Item = Result<Bytes, io::Error>> + Unpin,
{
inner: S,
buffer: BytesMut,
found_stream: bool,
remaining: usize,
}
impl<S> UmpTransformStream<S>
where
S: Stream<Item = Result<Bytes, io::Error>> + Unpin,
{
pub fn new(stream: S) -> Self {
UmpTransformStream {
inner: stream,
buffer: BytesMut::new(),
found_stream: false,
remaining: 0,
}
}
}
impl<S> Stream for UmpTransformStream<S>
where
S: Stream<Item = Result<Bytes, io::Error>> + Unpin,
{
type Item = Result<Bytes, io::Error>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
while let Poll::Ready(item) = Pin::new(&mut this.inner).poll_next(cx) {
match item {
Some(Ok(bytes)) => {
if this.found_stream {
if this.remaining > 0 {
let len = std::cmp::min(this.remaining, bytes.len());
this.remaining -= len;
if this.remaining == 0 {
this.buffer.clear();
this.buffer.extend_from_slice(&bytes[len..]);
this.found_stream = false;
}
return Poll::Ready(Some(Ok(bytes.slice(0..len))));
} else {
this.found_stream = false;
this.buffer.clear();
this.buffer.extend_from_slice(&bytes);
};
} else {
this.buffer.extend_from_slice(&bytes);
}
}
Some(Err(e)) => return Poll::Ready(Some(Err(e))),
None => {
return Poll::Ready(None);
}
}
}
if !this.found_stream && !this.buffer.is_empty() {
let (segment_type, s1) = match read_variable_integer(&this.buffer, 0) {
Ok(result) => result,
Err(_) => return Poll::Pending,
};
let (segment_length, s2) = match read_variable_integer(&this.buffer, s1) {
Ok(result) => result,
Err(_) => return Poll::Pending,
};
if segment_type != 21 {
// Not the stream
if this.buffer.len() > s1 + s2 + segment_length as usize {
let _ = this.buffer.split_to(s1 + s2 + segment_length as usize);
}
} else {
this.remaining = segment_length as usize - 1;
let _ = this.buffer.split_to(s1 + s2 + 1);
if this.buffer.len() > segment_length as usize {
let len = std::cmp::min(this.remaining, this.buffer.len());
this.remaining -= len;
return Poll::Ready(Some(Ok(this.buffer.split_to(len).into())));
} else {
this.remaining -= this.buffer.len();
this.found_stream = true;
return Poll::Ready(Some(Ok(this.buffer.to_vec().into())));
}
}
}
Poll::Pending
}
}

103
src/utils.rs Normal file
View file

@ -0,0 +1,103 @@
use qstring::QString;
use reqwest::Url;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::env;
pub fn read_buf(buf: &[u8], pos: &mut usize) -> u8 {
let byte = buf[*pos];
*pos += 1;
byte
}
fn finalize_url(path: &str, query: BTreeMap<String, String>) -> String {
#[cfg(feature = "qhash")]
{
use std::collections::BTreeSet;
let qhash = {
let secret = env::var("HASH_SECRET");
if let Ok(secret) = secret {
let set = query
.iter()
.filter(|(key, _)| !matches!(key.as_str(), "qhash" | "range" | "rewrite"))
.map(|(key, value)| (key.as_bytes().to_owned(), value.as_bytes().to_owned()))
.collect::<BTreeSet<_>>();
let mut hasher = blake3::Hasher::new();
for (key, value) in set {
hasher.update(&key);
hasher.update(&value);
}
hasher.update(path.as_bytes());
hasher.update(secret.as_bytes());
let hash = hasher.finalize().to_hex();
Some(hash[..8].to_owned())
} else {
None
}
};
if let Some(qhash) = qhash {
let mut query = QString::new(query.into_iter().collect::<Vec<_>>());
query.add_pair(("qhash", qhash));
return format!("{}?{}", path, query);
}
}
let query = QString::new(query.into_iter().collect::<Vec<_>>());
format!("{}?{}", path, query)
}
pub fn localize_url(url: &str, host: &str) -> String {
if url.starts_with("https://") {
let url = Url::parse(url).unwrap();
let host = url.host().unwrap().to_string();
let mut query = url.query_pairs().into_owned().collect::<BTreeMap<_, _>>();
query.insert("host".to_string(), host.clone());
return finalize_url(url.path(), query);
} else if url.ends_with(".m3u8") || url.ends_with(".ts") {
let mut query = BTreeMap::new();
query.insert("host".to_string(), host.to_string());
return finalize_url(url, query);
}
url.to_string()
}
pub fn escape_xml(raw: &str) -> Cow<'_, str> {
if !raw.contains(&['<', '>', '&', '\'', '"'][..]) {
// If there are no characters to escape, return the original string.
Cow::Borrowed(raw)
} else {
// If there are characters to escape, build a new string with the replacements.
let mut escaped = String::with_capacity(raw.len());
for c in raw.chars() {
match c {
'<' => escaped.push_str("&lt;"),
'>' => escaped.push_str("&gt;"),
'&' => escaped.push_str("&amp;"),
'\'' => escaped.push_str("&apos;"),
'"' => escaped.push_str("&quot;"),
_ => escaped.push(c),
}
}
Cow::Owned(escaped)
}
}
pub fn get_env_bool(key: &str) -> bool {
match env::var(key) {
Ok(val) => val.to_lowercase() == "true" || val == "1",
Err(_) => false,
}
}