Compare commits

...

642 Commits

Author SHA1 Message Date
Alejandro
cf843c3f12 Text corrections 2023-12-06 08:45:06 +01:00
Alejandro
6966f37c4b Corrected reference to production.yaml 2023-12-06 08:45:06 +01:00
Chocobozzz
4fd8d34175
Ensure user is owned by plugin before updating it 2023-12-06 08:43:19 +01:00
Chocobozzz
c6047e1573
Add missing logger tags 2023-11-29 16:31:29 +01:00
Chocobozzz
f51bafb3fa
Fix chapters tests 2023-11-29 15:01:46 +01:00
Chocobozzz
f9e710e7d4
Fix chapters import 2023-11-29 14:12:13 +01:00
Julien Rabier
7a953a6b2f Fix upgrade.sh when Peertube is installed outside the standard path (fixes #6063) 2023-11-29 11:03:44 +01:00
Chocobozzz
d897a04565
Bumped to version v6.0.1 2023-11-29 10:20:14 +01:00
Chocobozzz
67cfea4270
Fix changelog 2023-11-29 10:19:33 +01:00
Chocobozzz
df2d931f66
Update changelog 2023-11-29 10:18:47 +01:00
Chocobozzz
ba56aadb63
Regenerate storyboard after studio 2023-11-29 09:58:20 +01:00
Chocobozzz
4826cb2c69
Add missing jobs in jobs list 2023-11-29 09:37:57 +01:00
Chocobozzz
bda1d751a5
Add warning for web_videos directory name 2023-11-29 09:28:12 +01:00
Chocobozzz
9f9522e865
Fix release script 2023-11-29 08:33:39 +01:00
Chocobozzz
6c89755d04
Fix changelog 2023-11-29 08:16:19 +01:00
Chocobozzz
ee6844d718
Fix web videos directory important notes 2023-11-29 08:10:26 +01:00
Chocobozzz
c900788e59
Remove async-lru cache for jsonld
jsonld library has already a cache
2023-11-29 06:51:29 +01:00
Chocobozzz
a5bdce80f6
Keep increasing storyboard generation ttl 2023-11-28 15:42:48 +01:00
Chocobozzz
e25f7b97e9
Typo in changelog 2023-11-28 14:18:35 +01:00
Chocobozzz
db61334cc3
Fix replace file nginx configuration 2023-11-28 14:11:07 +01:00
Chocobozzz
17f1920658
Fix CPU going to 100% on odd cpu count
See https://github.com/piscinajs/piscina/pull/457
2023-11-28 13:32:51 +01:00
Chocobozzz
e3d4259e14
Bumped to version v6.0.0 2023-11-28 08:40:29 +01:00
Chocobozzz
8bb42bda52
Fix search index tests 2023-11-28 08:31:47 +01:00
Chocobozzz
a0606360a7
Return 400 if filter query is still there 2023-11-28 08:08:57 +01:00
Chocobozzz
d3849e9b22
Update changelog 2023-11-27 16:21:09 +01:00
Chocobozzz
13b78db38e
Cleanup input switch 2023-11-27 10:11:29 +01:00
Chocobozzz
f3907ceeaf
Fix client registration performance 2023-11-27 09:15:42 +01:00
Chocobozzz
2703129a1a
Update translations 2023-11-27 08:42:40 +01:00
Chocobozzz
424108b98d
Merge remote-tracking branch 'weblate/develop' into develop 2023-11-27 08:40:57 +01:00
Chocobozzz
05d6520b22
Fix input switch accessibility 2023-11-27 08:37:20 +01:00
Ettore Atalan
14f8a9ba30 Translated using Weblate (German)
Currently translated at 97.1% (2183 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 16:12:22 +01:00
Ettore Atalan
2508492635 Translated using Weblate (German)
Currently translated at 96.2% (2162 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 15:51:38 +01:00
Ettore Atalan
a2c0cade2e Translated using Weblate (German)
Currently translated at 95.7% (2151 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 15:43:11 +01:00
Ettore Atalan
cc90c153e7 Translated using Weblate (German)
Currently translated at 94.6% (2126 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 15:35:38 +01:00
Ettore Atalan
b1e23d9990 Translated using Weblate (German)
Currently translated at 94.5% (2124 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 15:33:00 +01:00
Ettore Atalan
491aac98e0 Translated using Weblate (German)
Currently translated at 94.5% (2123 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-11-25 00:36:04 +01:00
Chocobozzz
11f40299c5
Workaround to fix bug where CPU at 100%
Commit b017d4d02f does not seem to work
2023-11-24 18:11:11 +01:00
BGR2
77b23551b0 Translated using Weblate (Turkish)
Currently translated at 36.2% (815 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/tr/
2023-11-24 14:52:02 +01:00
Chocobozzz
f3e9a38d7e
Fix tests build 2023-11-24 14:51:31 +01:00
Chocobozzz
b017d4d02f
Fix weird bug where CPU jumps and stays to 100%
Seems related to lazy import of custom-jsonld-signature
So we refactored jsonld function calls a little bit
2023-11-24 14:44:18 +01:00
Chocobozzz
f93bc6a8be
Retry runner job db saving if needed 2023-11-24 14:44:04 +01:00
Chocobozzz
6349881dbd
Fix graph zooming end date 2023-11-23 09:40:04 +01:00
Chocobozzz
80efccf6c5
Add autofocus to password prompt 2023-11-23 08:58:53 +01:00
Chocobozzz
b13460a10a
Add ability to set password from embed API 2023-11-23 08:14:54 +01:00
Chocobozzz
4c07200d64
CSS consistency on small screens 2023-11-22 08:28:22 +01:00
Chocobozzz
5ef3378534
Log piscina errors 2023-11-21 17:35:36 +01:00
Chocobozzz
aeea2d864f
Limit max piscina threads bases on CPUs 2023-11-21 17:25:44 +01:00
Chocobozzz
76fc448ab4
Bumped to version v6.0.0-rc.2 2023-11-20 10:44:50 +01:00
Chocobozzz
3f50a1bf25
Update translations 2023-11-20 09:48:48 +01:00
Chocobozzz
bbfa4208a0
Merge remote-tracking branch 'weblate/develop' into develop 2023-11-20 09:46:54 +01:00
Chocobozzz
e7e2bb4374
Update changelog 2023-11-20 09:46:43 +01:00
Chocobozzz
79a61fa9c6
Prevent player mobile buttons flickering 2023-11-20 09:42:54 +01:00
Hồ Nhất Duy
6f3a118be8 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-11-20 07:11:20 +01:00
Aitor Salaberria
d90b8678cb Translated using Weblate (Basque)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-20 07:11:20 +01:00
Jiri Podhorecky
82bc692d2b Translated using Weblate (Czech)
Currently translated at 99.8% (2243 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-11-20 07:11:20 +01:00
Jiri Podhorecky
b68f7955b4 Translated using Weblate (Czech)
Currently translated at 98.7% (2218 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-11-20 07:11:20 +01:00
Jiri Podhorecky
734f5e10ba Translated using Weblate (Czech)
Currently translated at 98.5% (2213 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-11-20 07:11:20 +01:00
Jiri Podhorecky
6151833116 Translated using Weblate (Czech)
Currently translated at 98.1% (2205 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-11-20 07:11:19 +01:00
alex gabilondo
671d2963ec Translated using Weblate (Basque)
Currently translated at 100.0% (142 of 142 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/eu/
2023-11-20 07:11:19 +01:00
alex gabilondo
4fdf3a1227 Translated using Weblate (Basque)
Currently translated at 100.0% (274 of 274 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/eu/
2023-11-20 07:11:19 +01:00
DignifiedSilence
fdd5c877fb Translated using Weblate (Japanese)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-11-20 07:11:19 +01:00
T.S
2f78d97127 Translated using Weblate (Japanese)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-11-20 07:11:19 +01:00
T.S
6e3700b0df Translated using Weblate (Japanese)
Currently translated at 99.4% (2234 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-11-20 07:11:19 +01:00
DignifiedSilence
aad5ea84ab Translated using Weblate (Japanese)
Currently translated at 99.4% (2234 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-11-20 07:11:19 +01:00
T.S
feac6c5ddd Translated using Weblate (Japanese)
Currently translated at 99.3% (2231 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-11-20 07:11:19 +01:00
Ignacio Carrera González
4e1fd1a330 Translated using Weblate (Spanish)
Currently translated at 95.2% (2139 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/es/
2023-11-20 07:11:19 +01:00
Jeff Huang
9c14f18f04 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-11-20 07:11:19 +01:00
josé m
76a6c7c0ae Translated using Weblate (Galician)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gl/
2023-11-20 07:11:19 +01:00
0que
a08ce33ad0 Translated using Weblate (Russian)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-11-20 07:11:19 +01:00
Александр
dadd88aa58 Translated using Weblate (Russian)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-11-20 07:11:19 +01:00
Chocobozzz
d4f21493e1
Respect "transcode original resolution" for runner 2023-11-17 16:25:11 +01:00
Chocobozzz
1682b0bab0
Increase generate-video-storyboard job ttl
See https://github.com/Chocobozzz/PeerTube/issues/6029
2023-11-17 16:24:55 +01:00
Chocobozzz
92fb7a2b62
Optimize homepage videos query 2023-11-17 14:40:37 +01:00
fuomag9
1e3fd73cdf Inform the user to remove assets:/app/client/dist if not using the webserver container 2023-11-17 14:23:31 +01:00
Chocobozzz
5b43602457
Fix card font color theme 2023-11-17 11:29:08 +01:00
Chocobozzz
33c707616c
Disable p2p seeding using local storage
Used by E2E testing
2023-11-15 11:06:18 +01:00
Chocobozzz
d8f846c69d
Add 'main' field to peertube types 2023-11-13 10:30:39 +01:00
Chocobozzz
929e05007c
Update translations 2023-11-09 09:05:23 +01:00
Chocobozzz
07de9791cf
Merge remote-tracking branch 'weblate/develop' into develop 2023-11-09 09:03:55 +01:00
Chocobozzz
3c668a1704
Update changelog 2023-11-09 09:03:32 +01:00
Chocobozzz
3da9fbbe39
Adapt storyboard sprite ratio 2023-11-09 09:03:32 +01:00
Chocobozzz
c2cf26eaf7
Less space below player in portrait mode 2023-11-09 09:03:32 +01:00
Hồ Nhất Duy
1bda457656 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-11-09 06:41:08 +01:00
Jeff Huang
5312bb7819 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-11-09 06:41:08 +01:00
0que
538ea58d68 Translated using Weblate (Russian)
Currently translated at 99.2% (141 of 142 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ru/
2023-11-09 06:41:08 +01:00
0que
7e5a1a42c1 Translated using Weblate (Russian)
Currently translated at 98.9% (271 of 274 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/ru/
2023-11-09 06:41:08 +01:00
0que
c0006c9a10 Translated using Weblate (Russian)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-11-09 06:41:08 +01:00
Mamiako Pavel
13dbea1103 Translated using Weblate (Russian)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-11-09 06:41:08 +01:00
Anatoly Bogomolov
f544ef3647 Translated using Weblate (Russian)
Currently translated at 100.0% (2246 of 2246 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-11-09 06:41:08 +01:00
Sarah Lewis
adfce264a6
Improve grammar within sign-up flow (#6026)
* Update signup-success-after-email.component.html

* Update signup-success-before-email.component.html
2023-11-09 06:41:03 +01:00
Chocobozzz
7ca4de2d98
Update page title and description on video change 2023-11-08 16:03:49 +01:00
Chocobozzz
dbd0a3bcac
Fix player ratio on mobile with portrait videos 2023-11-08 15:56:56 +01:00
Chocobozzz
ae16f5f115
Improve tools doc using code blocks
See the result on https://docs.joinpeertube.org/maintain/tools
2023-11-08 15:25:17 +01:00
Chocobozzz
dbb54df6bd
Add doc to move videos to filesystem 2023-11-08 15:05:32 +01:00
Chocobozzz
cc747fd67d
Uncomment doc regarding storyboard generation 2023-11-08 15:03:07 +01:00
Chocobozzz
5b394e1622
Increase test timeouts 2023-11-08 13:48:22 +01:00
Chocobozzz
ee8f377515
Update codeql ci 2023-11-08 10:53:32 +01:00
Chocobozzz
2bc4d26b94
Add ability to customize frames to analyze 2023-11-08 10:18:39 +01:00
Chocobozzz
9880d2adf5
Improve changelog 2023-11-08 09:39:44 +01:00
Chocobozzz
6e613df63f
Fix notification scrolling 2023-11-07 11:19:36 +01:00
Chocobozzz
624da0b0a4
Fix live button with multiple words 2023-11-07 11:17:28 +01:00
Chocobozzz
788fa301f2
Don't send views for private videos 2023-11-07 10:46:08 +01:00
Chocobozzz
1ba8bbded0
Also use 127.0.0.1 for database and redis
Node 18 can resolve localhost to IPv6 address, where postgresql and/or
redis may listen on IPv4 only
2023-11-07 10:41:08 +01:00
Chocobozzz
2d4274769e
Fix production.yaml.new config generation 2023-11-07 10:25:15 +01:00
Chocobozzz
5dd39c07a7
Bumped to version v6.0.0-rc.1 2023-11-07 08:49:09 +01:00
Chocobozzz
a193cfdd83
Update changelog 2023-11-07 08:49:06 +01:00
Chocobozzz
610f851651
Update translations 2023-11-07 08:17:32 +01:00
Chocobozzz
9b3b64cd44
Merge remote-tracking branch 'weblate/develop' into develop 2023-11-07 08:16:04 +01:00
Murat Özalp
1908e10d95 Translated using Weblate (Turkish)
Currently translated at 34.6% (775 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/tr/
2023-11-06 20:26:25 +01:00
GunChleoc
fbf64af51a Translated using Weblate (Gaelic)
Currently translated at 98.7% (2212 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-11-06 17:40:50 +01:00
Chocobozzz
193e752c44
Increase test timeouts 2023-11-06 14:04:43 +01:00
Txopi
e5d6197487 Translated using Weblate (Basque)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-06 11:57:10 +01:00
Free coss
cefdc74e26 Translated using Weblate (Arabic)
Currently translated at 96.0% (2151 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-11-06 11:57:10 +01:00
Jaz Dina
329344e869 Translated using Weblate (Spanish)
Currently translated at 95.9% (2149 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/es/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
1f7a91c47e Translated using Weblate (Basque)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
cf1727cdd5 Translated using Weblate (Basque)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
b31a4bf682 Translated using Weblate (Basque)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
582e3f97b0 Translated using Weblate (Basque)
Currently translated at 100.0% (142 of 142 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/eu/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
e7183d1ee7 Translated using Weblate (Basque)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-11-06 11:57:10 +01:00
Aitor Salaberria
8b7f1c1d80 Translated using Weblate (Spanish)
Currently translated at 94.6% (2120 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/es/
2023-11-06 11:57:10 +01:00
Chocobozzz
a21b7a4193
Update changelog 2023-11-06 11:54:41 +01:00
Chocobozzz
4aeb1de909
Update p2p media loader 2023-11-06 11:20:23 +01:00
Chocobozzz
b1fc5a9cb4
Add log level example in docker .env 2023-11-06 08:59:38 +01:00
Chocobozzz
96bb9de7d0
Fix E2E tests 2023-11-06 08:56:56 +01:00
Chocobozzz
d3c9a2e5b9
Add script to move videos to file system 2023-11-02 09:21:49 +01:00
Chocobozzz
443358ccce
Reduce video comment sql query size 2023-10-31 10:02:19 +01:00
Chocobozzz
2e556debca
Fix log error 2023-10-30 14:14:19 +01:00
Chocobozzz
15f2ac7152
Fix invalid timeout 2023-10-30 11:58:43 +01:00
Chocobozzz
543fbd1ffe
Correctly display broken muxing session
Can happen when we stream an audio stream only
2023-10-30 11:57:39 +01:00
Chocobozzz
ad801093b9
Simplify for loop 2023-10-30 11:17:46 +01:00
Chocobozzz
98ddba6808
Update translations 2023-10-30 11:13:13 +01:00
Chocobozzz
e0c0089366
Merge remote-tracking branch 'weblate/develop' into develop 2023-10-30 11:11:51 +01:00
Aitor Salaberria
c3a999d7ab Translated using Weblate (Basque)
Currently translated at 85.9% (1924 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-30 11:11:48 +01:00
Chocobozzz
04bd31bc18
Add more live latency info in stats for nerds 2023-10-30 11:08:09 +01:00
Chocobozzz
a12d94f30d
Fix live start time
Use undefined to not break live edge position set by hls.js
2023-10-30 11:04:26 +01:00
Chocobozzz
19dbbdafcc
Fix local E2E timeout 2023-10-30 10:32:37 +01:00
Chocobozzz
078c97b357
Add chapter cache to time tooltip 2023-10-30 10:25:14 +01:00
Chocobozzz
4fa78cda92
Fix timetoint
01:02 was translated to 01h02m instead of 01m02s
2023-10-30 10:20:25 +01:00
Chocobozzz
22e05d15db
Fix video error handling 2023-10-30 09:55:06 +01:00
Chocobozzz
f108600464
Fix CI 2023-10-30 09:09:55 +01:00
0que
15eb78797c Translated using Weblate (Russian)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ru/
2023-10-29 16:14:45 +01:00
0que
5d5255dfe9 Translated using Weblate (Russian)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/ru/
2023-10-29 16:14:45 +01:00
0que
46fc4852e8 Translated using Weblate (Russian)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-29 16:14:45 +01:00
Aitor Salaberria
766203fa94 Translated using Weblate (Basque)
Currently translated at 85.9% (1924 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-29 16:14:44 +01:00
Aitor Salaberria
1025145c9f Translated using Weblate (Basque)
Currently translated at 85.1% (1906 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-28 23:57:47 +02:00
Aitor Salaberria
0de9ec0013 Translated using Weblate (Basque)
Currently translated at 79.8% (1787 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-28 09:02:49 +02:00
Free coss
384d219a73 Translated using Weblate (Arabic)
Currently translated at 95.9% (2148 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Ryan He
22ef09a1a6 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/zh_Hant/
2023-10-27 17:16:22 +02:00
Ryan He
d03d340efc Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/zh_Hant/
2023-10-27 17:16:22 +02:00
Ryan He
a427d1d67b Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-10-27 17:16:22 +02:00
Free coss
0aa4c0cd40 Translated using Weblate (Arabic)
Currently translated at 87.2% (1953 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Free coss
a68dfc4feb Translated using Weblate (Arabic)
Currently translated at 86.4% (1936 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Free coss
22f1e6d782 Translated using Weblate (Arabic)
Currently translated at 86.2% (1931 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Free coss
d96d921ffd Translated using Weblate (Arabic)
Currently translated at 85.5% (1916 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Free coss
102f4b9f80 Translated using Weblate (Arabic)
Currently translated at 85.3% (1910 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
Free coss
3cc67f91b4 Translated using Weblate (Arabic)
Currently translated at 85.0% (1905 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-27 17:16:22 +02:00
josé m
abb8ca1c32 Translated using Weblate (Galician)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gl/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
76eae1ea77 Translated using Weblate (Basque)
Currently translated at 78.7% (1764 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Cokelat8
77c654adfc Translated using Weblate (Indonesian)
Currently translated at 98.0% (100 of 102 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/id/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
c8de359c57 Translated using Weblate (Basque)
Currently translated at 78.4% (1756 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Cokelat8
5b8179e758 Translated using Weblate (Indonesian)
Currently translated at 97.0% (99 of 102 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/id/
2023-10-27 17:16:22 +02:00
Cokelat8
238bb87189 Translated using Weblate (Indonesian)
Currently translated at 30.7% (75 of 244 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/id/
2023-10-27 17:16:22 +02:00
Cokelat8
20c2156b4d Translated using Weblate (Indonesian)
Currently translated at 12.8% (224 of 1748 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/id/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
55530ad896 Translated using Weblate (Basque)
Currently translated at 77.4% (1734 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Mikel Gartzia Santamaria
f7f326a083 Translated using Weblate (Basque)
Currently translated at 77.2% (1730 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
ca0a77be53 Translated using Weblate (Basque)
Currently translated at 77.2% (1730 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
90cf61ec62 Translated using Weblate (Basque)
Currently translated at 71.5% (1601 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Aitor Salaberria
252999db9a Translated using Weblate (Basque)
Currently translated at 67.3% (1508 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-27 17:16:22 +02:00
Chocobozzz
507467b6a6
Fix local e2e tests 2023-10-27 16:53:41 +02:00
Chocobozzz
880f8b924d
Add worker thread completed OTEL metric 2023-10-27 14:40:53 +02:00
Chocobozzz
049f50bc32
Fix start time with web video player 2023-10-27 14:29:40 +02:00
Chocobozzz
2809ebbc20
Fix playlist element title overflow 2023-10-27 11:27:10 +02:00
Chocobozzz
414875a220
Fix running server in E2E tests 2023-10-27 10:44:01 +02:00
Chocobozzz
0c63b37eb3
Remove unnecessary wdio services
See https://webdriver.io/blog/2023/07/31/driver-management/
2023-10-27 10:22:38 +02:00
Chocobozzz
09ab8e577c
Increase timeouts 2023-10-26 16:41:19 +02:00
Chocobozzz
a2d5c2d44f
Add worker thread queue metrics 2023-10-26 16:34:54 +02:00
Chocobozzz
bbd7de5c9d
CI can be very slow 2023-10-26 15:23:07 +02:00
Chocobozzz
606c044dc8
Fix uploading empty master playlist on s3 2023-10-26 15:14:14 +02:00
Chocobozzz
3bd4637014
Also skip count for recommendation fallback 2023-10-26 14:50:20 +02:00
Chocobozzz
f9bbcd4ba2
Fix stats X axis with old videos 2023-10-26 14:43:50 +02:00
Chocobozzz
40a6dcb632
Optimize video views redis calls
Try to avoid them if we can
2023-10-26 14:08:19 +02:00
Chocobozzz
0f21769205
Don't log http request to benchmark views api 2023-10-26 12:30:34 +02:00
Chocobozzz
de862fd0e7
Optimize video viewer stats
Many Redis (and so network) calls can be expensive
Avoid them if we can by using in memory cache
2023-10-26 11:35:55 +02:00
Chocobozzz
8ecf95471d
Also remove video session on muxing error 2023-10-26 09:07:26 +02:00
Chocobozzz
dd7de7e32d
Don't add a LIMIT 1 to prevent seq scan 2023-10-26 08:36:53 +02:00
Chocobozzz
d3dd952cc5
Try to optimize tagsOneOf/tagsAllOf SQL queries
Using a CTE because the query will probably return a few results
I tried a IN clause but PG doesn't seem to be more efficient with it
The CTE seems to be the only choice
2023-10-25 16:15:41 +02:00
Chocobozzz
a290fbf821
Add isLive DB index 2023-10-25 15:07:36 +02:00
Chocobozzz
82813e9739
Optimize infohash SQL query
We need to use the array operator to use GIN index
2023-10-25 15:04:00 +02:00
Chocobozzz
360439088d
Skip counting for recommended videos 2023-10-25 14:55:06 +02:00
Chocobozzz
cb38deb288
Process unicast job in a worker too
Signing the request can take a long time
2023-10-25 09:43:57 +02:00
Chocobozzz
90db2b3aed
Add ability to disable HTTP logs 2023-10-24 10:57:41 +02:00
Chocobozzz
edc3ff6085
Sign JSON objects in worker threads 2023-10-24 10:45:17 +02:00
Chocobozzz
9e2166a16f
Prepare changelog 2023-10-23 14:16:15 +02:00
Chocobozzz
004c9779d2
Update translations 2023-10-23 09:07:08 +02:00
Chocobozzz
40723fb79d
Merge remote-tracking branch 'weblate/develop' into develop 2023-10-23 08:57:59 +02:00
Chocobozzz
18dd8fd541
Upgrade ng-select to fix cross icon accessibility 2023-10-23 08:57:24 +02:00
Aitor Salaberria
decc4f7945 Translated using Weblate (Basque)
Currently translated at 66.3% (1486 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-22 21:32:17 +02:00
Free coss
583340a6ce Translated using Weblate (Arabic)
Currently translated at 85.1% (1907 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-22 16:51:05 +02:00
Free coss
1839e9a987 Translated using Weblate (Arabic)
Currently translated at 80.3% (1798 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-22 14:15:51 +02:00
Aitor Salaberria
4dbb9575fc Translated using Weblate (Basque)
Currently translated at 64.8% (1451 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-22 14:15:45 +02:00
Aitor Salaberria
b0c8bb3bd9 Translated using Weblate (Basque)
Currently translated at 63.2% (1416 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-22 13:20:39 +02:00
Aitor Salaberria
fb5d877dc2 Translated using Weblate (Basque)
Currently translated at 58.3% (1306 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-22 01:23:57 +02:00
Aitor Salaberria
3cf52ac344 Translated using Weblate (Basque)
Currently translated at 56.4% (1265 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-21 20:14:11 +02:00
Aitor Salaberria
17f5bdea01 Translated using Weblate (Basque)
Currently translated at 55.9% (1252 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-21 18:33:06 +02:00
Aitor Salaberria
e914cf7353 Translated using Weblate (Basque)
Currently translated at 55.2% (1236 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-21 14:00:44 +02:00
Hồ Nhất Duy
0687f186ed Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-10-21 06:26:12 +02:00
Filip Hanes
d178c11e08 Translated using Weblate (Slovak)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-10-20 17:31:00 +02:00
Александр
6ed7db797a Translated using Weblate (Russian)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-20 17:31:00 +02:00
DignifiedSilence
a0d290deb9 Translated using Weblate (Japanese)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-10-20 17:31:00 +02:00
Free coss
3c5bb11db6 Translated using Weblate (Arabic)
Currently translated at 80.1% (1794 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-20 17:31:00 +02:00
Jeff Huang
385c55eac8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-10-20 17:31:00 +02:00
Ihor Hordiichuk
d3c41554e6 Translated using Weblate (Ukrainian)
Currently translated at 98.5% (2207 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-10-20 17:31:00 +02:00
Александр
5a3cc6fac5 Translated using Weblate (Russian)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-20 17:31:00 +02:00
josé m
85e16cf2d5 Translated using Weblate (Galician)
Currently translated at 100.0% (2239 of 2239 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gl/
2023-10-20 17:31:00 +02:00
Chocobozzz
b7f1bc0c33
Fix misc endpoints tests 2023-10-20 17:30:46 +02:00
Chocobozzz
521face89e
Add embed info jsonld in embeds too 2023-10-20 16:15:45 +02:00
Chocobozzz
757ffb2a69
Add peertube version info in openapi doc 2023-10-20 16:09:08 +02:00
Chocobozzz
53fdb2e83e
Fix server build 2023-10-20 16:05:38 +02:00
Chocobozzz
a74fe0b69a
Remove unused polyfill
Only needed by ios versions we don't support anymore
2023-10-20 16:00:53 +02:00
Chocobozzz
8e15a31e98
Fix overflow on videos list pages 2023-10-20 16:00:36 +02:00
Chocobozzz
f90db24233
Fix SEO and refactor HTML pages generation
* Split methods in multiple classes
 * Add JSONLD tags in embed too
 * Index embeds but use a canonical URL tag (targeting the watch page)
 * Remote objects don't include a canonical URL tag anymore. Instead we
   forbid indexation
 * Canonical URLs now use the official short URL (/w/, /w/p, /a, /c
   etc.)
2023-10-20 16:00:36 +02:00
Chocobozzz
e731f4b724
Fix sitemap URL for accounts and channels 2023-10-20 16:00:36 +02:00
Chocobozzz
58daa2d97b
More flexible way to forbid indexation 2023-10-20 16:00:36 +02:00
Chocobozzz
272a902b2a
Optimize video thumbnail generation
Process images in worker threads
Reduce ffmpeg calls
2023-10-20 16:00:36 +02:00
Wicklow
ea6c2b064f
Allow to change the default channel name (#6000)
* Allow to change the default channel name

* Fix tests

* Fix tests

* Fix tests
2023-10-19 15:22:00 +02:00
Chocobozzz
ae468445b2
Increase other test timeouts 2023-10-18 15:57:11 +02:00
Chocobozzz
0397b31efe
Reduce views tests load 2023-10-18 15:53:17 +02:00
Chocobozzz
830907ec93
Increase test timeouts 2023-10-18 15:53:08 +02:00
Chocobozzz
3546128f95
Workaround to bullmq undefined jobs 2023-10-18 15:46:18 +02:00
Chocobozzz
ea01bf0167
Increase tests timeout 2023-10-13 09:59:59 +02:00
Chocobozzz
75d5a23dbc
Prevent error when removing a streaming playlist 2023-10-13 09:59:18 +02:00
Chocobozzz
81a51d4bb1
Fix chapters markers in progress bar
Fix when we update the video source
Fix when we don't have the video duration yet when creating markers
2023-10-12 16:03:20 +02:00
Chocobozzz
58fda6d416
Fix upload with chapters having non int timecode 2023-10-12 15:32:01 +02:00
Chocobozzz
ed0852f1b8
Update translations 2023-10-12 15:19:52 +02:00
Free coss
4b428a7e76 Translated using Weblate (Arabic)
Currently translated at 78.3% (1749 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Free coss
37b4c33ab9 Translated using Weblate (Arabic)
Currently translated at 75.3% (1682 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Free coss
bce22ae0a9 Translated using Weblate (Arabic)
Currently translated at 75.2% (1680 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Free coss
2c926a6933 Translated using Weblate (Arabic)
Currently translated at 74.1% (1655 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Free coss
d8e7e759a1 Translated using Weblate (Arabic)
Currently translated at 74.0% (1652 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Milo Ivir
f95073d75a Translated using Weblate (Croatian)
Currently translated at 100.0% (2232 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-10-12 15:17:51 +02:00
Hồ Nhất Duy
632c1e950d Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2232 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-10-12 15:17:51 +02:00
Aitor Salaberria
84f24c1c4c Translated using Weblate (Basque)
Currently translated at 55.4% (1237 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-12 15:17:51 +02:00
Free coss
aa41099522 Translated using Weblate (Arabic)
Currently translated at 73.5% (1641 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-12 15:17:51 +02:00
Aitor Salaberria
916964291a Translated using Weblate (Basque)
Currently translated at 55.0% (1228 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-12 15:17:51 +02:00
Aitor Salaberria
5a4667a578 Translated using Weblate (Basque)
Currently translated at 54.4% (1215 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-12 15:17:51 +02:00
Aitor Salaberria
2c054f7d37 Translated using Weblate (Basque)
Currently translated at 53.7% (1200 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-12 15:17:51 +02:00
chocobozzz
688dfa7399 Translated using Weblate (French (France) (fr_FR))
Currently translated at 92.2% (2059 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fr_FR/
2023-10-12 15:17:51 +02:00
Jeff Huang
1253174105 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2232 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-10-12 15:17:51 +02:00
Ihor Hordiichuk
f14f622343 Translated using Weblate (Ukrainian)
Currently translated at 98.5% (2200 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-10-12 15:17:51 +02:00
Александр
db337cd1d5 Translated using Weblate (Russian)
Currently translated at 100.0% (2232 of 2232 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-12 15:17:51 +02:00
Chocobozzz
c6d2384aa7
Fix global buttons accessibility 2023-10-12 15:01:17 +02:00
Chocobozzz
d3ae2e9c80
Fix feed button 2023-10-12 14:24:48 +02:00
Chocobozzz
ce3d17388d
Fix remove file buttons accessibility 2023-10-12 14:24:38 +02:00
Chocobozzz
e94160c770
Fix playlist buttons accessibility 2023-10-12 14:24:22 +02:00
Chocobozzz
44e12dc809
Update bullmq dependency 2023-10-12 09:29:45 +02:00
Chocobozzz
a1c96a63a0
Better videos list header styling 2023-10-12 09:06:40 +02:00
Chocobozzz
5bd42bbca7
Fix resumable tests 2023-10-11 16:17:11 +02:00
Chocobozzz
7243393272
Fix signup and import 2023-10-11 15:58:16 +02:00
Chocobozzz
71ba1ead4f
Fix types test 2023-10-11 15:29:11 +02:00
Chocobozzz
fca58de835
Fix runner test 2023-10-11 15:13:54 +02:00
Chocobozzz
678ae8abbd
Breaking: only support node 18
Node 16 is not supported anymore

See https://nodejs.org/fr/blog/announcements/nodejs16-eol
2023-10-11 13:59:24 +02:00
Chocobozzz
13f07161f5
Do not display only "Older" period 2023-10-11 11:56:03 +02:00
Chocobozzz
e2c7e58f42
Fix input switch accessibility 2023-10-11 11:49:15 +02:00
Chocobozzz
30ad7fdf69
Upgrade client dependencies 2023-10-11 11:42:57 +02:00
Chocobozzz
2db1f3238d
Update server dependencies 2023-10-11 11:06:34 +02:00
Chocobozzz
066efd4b94
Add tooltip to know we can sort the column 2023-10-11 09:20:09 +02:00
Chocobozzz
d0cd721254
Fix focus visible on table row 2023-10-10 11:00:11 +02:00
Chocobozzz
58036ff463
Fix focus on table header cell with sort 2023-10-10 10:56:25 +02:00
Chocobozzz
dc5564258f
Fix focus information on table checkboxes 2023-10-10 10:49:22 +02:00
Chocobozzz
bc80e45a09
Fix table expand button accessibility 2023-10-10 09:16:33 +02:00
Chocobozzz
0d0b5ac08d
Fix custom bootstrap helpers margins/paddings 2023-10-10 09:11:50 +02:00
Chocobozzz
cf5ab8abf2
Add focus to important elements with tooltip 2023-10-10 09:04:56 +02:00
Chocobozzz
57abac459b
Fix registration button style 2023-10-10 08:41:35 +02:00
Chocobozzz
905a40217d
Fix logged in hotkeys 2023-10-10 08:35:53 +02:00
Chocobozzz
0bb768a712
padding/margin inline is supported by ios 12.1
So we don't need the @supports CSS rule anymore
2023-10-09 16:11:51 +02:00
Chocobozzz
50e415e12e
Allow to disable all hotkeys
Added angular2-hotkeys dependency inside PeerTube, to tweak some
settings

It will also allow us to support non latin keyboard in the future as we
can choose the "mouse trap" dependency
2023-10-09 15:33:19 +02:00
Chocobozzz
e6b455b4ea
Better title for the date component 2023-10-09 10:19:06 +02:00
Chocobozzz
9b879f69c4
Fix video playlist miniature tabindex 2023-10-09 10:09:17 +02:00
Chocobozzz
f47762c60b
Add global skip link
Don't use routerLink as some pages react on route params changes
Prefer to programmatically focus the main content if we can
2023-10-09 10:07:03 +02:00
Chocobozzz
bd4b321b0b
Add missing autocomplete fields 2023-10-09 09:50:59 +02:00
Chocobozzz
31a67bc620
Add placeholder to contact email input 2023-10-09 09:49:07 +02:00
Chocobozzz
62dd3ad573
Explain the filter button will close the filters 2023-10-09 09:41:54 +02:00
Chocobozzz
be42d9a2b4
Add radiogroup role 2023-10-09 09:38:08 +02:00
Chocobozzz
f84002001a
Fix search input accessibility label 2023-10-09 09:28:58 +02:00
Chocobozzz
28af325f99
Fix x overflow for search results 2023-10-09 09:21:43 +02:00
Chocobozzz
a41c908370
Improve simple/advanced search accessibility 2023-10-06 16:42:06 +02:00
Chocobozzz
f547ab7dd1
Fix tables on small devices 2023-10-06 15:13:50 +02:00
Chocobozzz
52319e371f
Fix top sub menu accessibility 2023-10-06 14:56:29 +02:00
Chocobozzz
8d20c8f391
Prevent setting color attribute on loading bar
Fire accessibility/HTML guidelines warnings/errors
2023-10-06 11:29:13 +02:00
Chocobozzz
04bc2e2dbe
Use lists for the left menu 2023-10-06 11:23:12 +02:00
Chocobozzz
dcf5075ae4
Use <header> and <main> 2023-10-06 10:47:39 +02:00
Chocobozzz
2861397f9d
Replace <menu> by <nav> for left menu 2023-10-06 10:45:42 +02:00
Chocobozzz
7938f1d5e6
Use h1 for hotkeys modal
And so hide what's behind the modal
2023-10-06 10:41:45 +02:00
Chocobozzz
1019aaf8e7
Avoid multiple <br /> tags 2023-10-06 10:29:42 +02:00
Chocobozzz
743db867f2
Remove invalid role on noscript tag 2023-10-06 10:19:58 +02:00
Chocobozzz
55d7e361f5
Add alert role to form error messages 2023-10-06 10:19:20 +02:00
Chocobozzz
54f16adca8
Add accessibility role to notification div 2023-10-06 10:17:44 +02:00
Chocobozzz
27243f96f1
Improve left menu toggle accessibility 2023-10-06 10:08:51 +02:00
Chocobozzz
ce99886db6
Improve search bar accessibility
Also remove the "X" icon from Chrome we don't want
2023-10-06 09:59:21 +02:00
Chocobozzz
e049e3ec73
Remove unused file 2023-10-06 09:59:18 +02:00
Chocobozzz
c5397bd066
Fix broadcast dismiss icon accessibility 2023-10-05 16:30:08 +02:00
Chocobozzz
84bcfdaeff
Add scope="col" to column headers 2023-10-05 16:20:15 +02:00
Chocobozzz
d6a31f9bef
Improve accessibility of empty column header 2023-10-05 16:13:12 +02:00
Chocobozzz
0ac3820f4d
Improve hotkeys popup accessibility 2023-10-05 15:56:36 +02:00
Chocobozzz
4d61e5ef9c
Improve video miniature link label accessibility 2023-10-05 15:43:24 +02:00
Chocobozzz
46dd167df6
Fix placeholder accesibility 2023-10-05 15:24:32 +02:00
Chocobozzz
f85ace9ebb
Improve alert links accessibility 2023-10-05 15:20:24 +02:00
Chocobozzz
e5eefaf7a5
Use aria hidden for global icons
We use them in buttons/links that already have accessible context
(title, content or label) or just as decorative icons (in menu for
example)
2023-10-05 15:05:24 +02:00
Chocobozzz
516479f113
Try to use atomic move for runner live 2023-10-05 11:09:11 +02:00
Chocobozzz
d970837922
Fix test paths 2023-10-04 15:40:33 +02:00
Chocobozzz
5a3d0650c9
server/server -> server/core 2023-10-04 15:13:25 +02:00
Chocobozzz
114327d4ce
Fix margin with big resolution labels 2023-10-04 14:08:01 +02:00
Chocobozzz
9257243620
Fix hls tests 2023-10-04 11:12:29 +02:00
Chocobozzz
0112cd3851
Update translations 2023-10-04 10:06:21 +02:00
Aitor Salaberria
195d724014 Translated using Weblate (Basque)
Currently translated at 51.5% (1149 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-04 10:01:10 +02:00
Ihor Hordiichuk
557a80b30b Translated using Weblate (Ukrainian)
Currently translated at 98.3% (2195 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-10-04 10:01:10 +02:00
Jeff Huang
aea1fd022c Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2231 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-10-04 10:01:10 +02:00
nexi
4fdf489324 Translated using Weblate (Serbian (cyrillic))
Currently translated at 14.6% (256 of 1747 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sr_Cyrl/
2023-10-04 10:01:10 +02:00
Filip Hanes
db6f6950dd Translated using Weblate (Slovak)
Currently translated at 100.0% (234 of 234 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/sk/
2023-10-04 10:01:10 +02:00
Filip Hanes
c015394fd4 Translated using Weblate (Slovak)
Currently translated at 100.0% (2231 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-10-04 10:01:10 +02:00
Александр
a655a8a100 Translated using Weblate (Russian)
Currently translated at 100.0% (2231 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-04 10:01:10 +02:00
Vri
62b2ee85c4 Translated using Weblate (German)
Currently translated at 95.4% (2129 of 2231 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/de/
2023-10-04 10:01:10 +02:00
Chocobozzz
d0f8a0e677
Fix mime type handling from remote instances 2023-10-04 09:59:27 +02:00
Chocobozzz
fbc7f1a00d
Fix video quality on high resolution/fps 2023-10-04 09:21:14 +02:00
Chocobozzz
1611721c9b
Fix feed audio file mimetype 2023-10-03 12:20:11 +02:00
Chocobozzz
5cea8f9567
Prevent remote subscribe on accounts
Which is not supported by PeerTube
2023-10-03 10:20:29 +02:00
Chocobozzz
3601872153
Support empty value returned by video get filter 2023-10-03 09:36:00 +02:00
Wicklow
9864a0cae1
Add brazilian option for video/captions languages (#5971)
* Add brazilian option for video/captions languages

* Respect default local region
2023-10-02 11:54:13 +02:00
Johnny Jazeix
86731e752a
Add Valencian option for video/captions languages (#5975) 2023-10-02 11:53:32 +02:00
Chocobozzz
4f718651dd
Update translations 2023-10-02 11:51:32 +02:00
chocobozzz
2c4065958e Translated using Weblate (Icelandic)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/is/
2023-10-02 11:42:56 +02:00
Filip Hanes
691523f1b0 Translated using Weblate (Slovak)
Currently translated at 100.0% (98 of 98 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/sk/
2023-10-02 11:24:51 +02:00
Filip Hanes
3b4d5a882f Translated using Weblate (Slovak)
Currently translated at 97.8% (229 of 234 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/sk/
2023-10-02 11:24:51 +02:00
Filip Hanes
a5a12bac9b Translated using Weblate (Slovak)
Currently translated at 89.3% (1990 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-10-02 11:24:51 +02:00
Aitor Salaberria
5e46d4a0df Translated using Weblate (Basque)
Currently translated at 48.5% (1081 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-02 11:24:51 +02:00
Filip Hanes
b84a741b78 Translated using Weblate (Slovak)
Currently translated at 2.3% (52 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-10-02 11:24:51 +02:00
Aitor Salaberria
923e636543 Translated using Weblate (Basque)
Currently translated at 43.3% (965 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-02 11:24:51 +02:00
Aitor Salaberria
71fe133884 Translated using Weblate (Basque)
Currently translated at 41.4% (923 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-02 11:24:51 +02:00
Jeston Tan
9156f3f5a0 Translated using Weblate (Chinese (Simplified))
Currently translated at 90.6% (2017 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hans/
2023-10-02 11:24:51 +02:00
Txopi
2839f33682 Translated using Weblate (Basque)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/eu/
2023-10-02 11:24:51 +02:00
Aitor Salaberria
27f274bf28 Translated using Weblate (Basque)
Currently translated at 41.1% (917 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-02 11:24:51 +02:00
Aitor Salaberria
d79884cf72 Translated using Weblate (Basque)
Currently translated at 40.6% (904 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-10-02 11:24:51 +02:00
Neko Nekowazarashi
45ec230569 Translated using Weblate (Indonesian)
Currently translated at 96.0% (98 of 102 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/id/
2023-10-02 11:24:51 +02:00
Neko Nekowazarashi
eb0e9180dd Translated using Weblate (Indonesian)
Currently translated at 29.9% (73 of 244 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/id/
2023-10-02 11:24:50 +02:00
Free coss
86f7074458 Translated using Weblate (Arabic)
Currently translated at 71.3% (1589 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-02 11:24:50 +02:00
Victor Hampel
9c64a6e0ab Translated using Weblate (German)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/de/
2023-10-02 11:24:50 +02:00
Victor Hampel
13e8f300a8 Translated using Weblate (German)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/de/
2023-10-02 11:24:50 +02:00
Free coss
9099a91c13 Translated using Weblate (Arabic)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/ar/
2023-10-02 11:24:50 +02:00
Free coss
dcc907e1ec Translated using Weblate (Arabic)
Currently translated at 71.3% (1589 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-02 11:24:50 +02:00
Eric Guichaoua
2198aa190d Translated using Weblate (French (France) (fr_FR))
Currently translated at 92.5% (2061 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fr_FR/
2023-10-02 11:24:50 +02:00
Jim Kats
fd6db1cb34 Translated using Weblate (Greek)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/el/
2023-10-02 11:24:50 +02:00
Jim Kats
f67ab92939 Translated using Weblate (Greek)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/el/
2023-10-02 11:24:50 +02:00
Jim Kats
cc66b565df Translated using Weblate (Greek)
Currently translated at 45.7% (1019 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/el/
2023-10-02 11:24:50 +02:00
Jim Kats
ad9a4006e8 Translated using Weblate (Greek)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/el/
2023-10-02 11:24:50 +02:00
Free coss
e687f6fbc6 Translated using Weblate (Arabic)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ar/
2023-10-02 11:24:50 +02:00
Free coss
3e81eeab51 Translated using Weblate (Arabic)
Currently translated at 70.8% (1577 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ar/
2023-10-02 11:24:50 +02:00
Hồ Nhất Duy
5b05d5dc8d Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-10-02 11:24:50 +02:00
nexi
948fade981 Translated using Weblate (Serbian (cyrillic))
Currently translated at 100.0% (102 of 102 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/sr_Cyrl/
2023-10-02 11:24:50 +02:00
Jiri Podhorecky
4f36f466f3 Translated using Weblate (Czech)
Currently translated at 98.9% (2202 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-10-02 11:24:50 +02:00
Besnik Bleta
8b1165d13a Translated using Weblate (Albanian)
Currently translated at 98.5% (139 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/sq/
2023-10-02 11:24:50 +02:00
no
b208072eec Translated using Weblate (Albanian)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/sq/
2023-10-02 11:24:50 +02:00
Balázs Meskó
044af75497 Translated using Weblate (Hungarian)
Currently translated at 73.2% (1631 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hu/
2023-10-02 11:24:50 +02:00
nexi
f51c1cb71c Translated using Weblate (Serbian (cyrillic))
Currently translated at 14.5% (255 of 1747 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sr_Cyrl/
2023-10-02 11:24:50 +02:00
Александр
1ad14eb413 Translated using Weblate (Russian)
Currently translated at 99.9% (2225 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-10-02 11:24:50 +02:00
GunChleoc
fb6a5539ea Translated using Weblate (Gaelic)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-10-02 11:24:50 +02:00
GunChleoc
85abebf5a6 Translated using Weblate (Gaelic)
Currently translated at 99.9% (2224 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-10-02 11:24:50 +02:00
nexi
03ffad7e14 Translated using Weblate (Serbian (cyrillic))
Currently translated at 100.0% (102 of 102 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/sr_Cyrl/
2023-10-02 11:24:50 +02:00
nexi
058d0bbe88 Translated using Weblate (Serbian (cyrillic))
Currently translated at 14.5% (254 of 1747 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sr_Cyrl/
2023-10-02 11:24:49 +02:00
nexi
8207c94dbc Translated using Weblate (Serbian (cyrillic))
Currently translated at 100.0% (244 of 244 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/sr_Cyrl/
2023-10-02 11:24:49 +02:00
Milo Ivir
6d706b6796 Translated using Weblate (Croatian)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-10-02 11:24:49 +02:00
Milo Ivir
4bbd1b9632 Translated using Weblate (Croatian)
Currently translated at 99.8% (2223 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-10-02 11:24:49 +02:00
Milo Ivir
228b46ec80 Translated using Weblate (Croatian)
Currently translated at 99.8% (2222 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-10-02 11:24:49 +02:00
josé m
fa1b0eb4d9 Translated using Weblate (Galician)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gl/
2023-10-02 11:24:49 +02:00
DignifiedSilence
cddd451af8 Translated using Weblate (Japanese)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ja/
2023-10-02 11:24:49 +02:00
T.S
cdf0e4cc1e Translated using Weblate (Japanese)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ja/
2023-10-02 11:24:49 +02:00
DignifiedSilence
3d0e097113 Translated using Weblate (Japanese)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/ja/
2023-10-02 11:24:49 +02:00
DignifiedSilence
b60db6ebe3 Translated using Weblate (Japanese)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-10-02 11:24:49 +02:00
Sveinn í Felli
712d69af01 Translated using Weblate (Icelandic)
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/is/
2023-10-02 11:24:49 +02:00
Jeff Huang
d67541f3c8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2226 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-10-02 11:24:49 +02:00
Payman Moghadam
3314c76ec5 Translated using Weblate (Persian)
Currently translated at 97.7% (2177 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-10-02 11:24:49 +02:00
Ihor Hordiichuk
36c73a9aef Translated using Weblate (Ukrainian)
Currently translated at 98.5% (2194 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-10-02 11:24:49 +02:00
GunChleoc
f2a6020934 Translated using Weblate (Gaelic)
Currently translated at 96.5% (2150 of 2226 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-10-02 11:24:48 +02:00
Chocobozzz
1022e27309
Fix live replay privacy change 2023-09-01 16:47:25 +02:00
Chocobozzz
a1d9318066
Stop live before removing files 2023-09-01 13:16:27 +02:00
Chocobozzz
d38a49463f
Fix disabling object storage ACL in docker 2023-09-01 11:41:38 +02:00
Julien Rabier
0216c3485d Fix path to Peertube installation in upgrade.sh 2023-09-01 11:07:37 +02:00
Chocobozzz
d2640682f6
Fix atom feed with science and technology category 2023-09-01 10:09:10 +02:00
Chocobozzz
0cc1a69881
Avoid federation error logs with likes on notes 2023-09-01 09:58:13 +02:00
Chocobozzz
c4799cd1b9
Avoid illegal characters in torrent filename 2023-09-01 09:55:08 +02:00
Chocobozzz
ca8a00d0e7
Fix ERR_HTTP_HEADERS_SENT crash 2023-09-01 09:27:57 +02:00
Chocobozzz
69601b66fe
Fix tests 2023-08-30 20:19:56 +02:00
Chocobozzz
6495764268
Fix chapters extract 2023-08-30 19:24:01 +02:00
Chocobozzz
76dbe843d1
Merge branch 'release/5.2.0' into develop 2023-08-30 19:03:03 +02:00
Chocobozzz
d8a80446da
Reduce ffmpeg thumbnail generation load
Can also lead to memory issues with big values (default is 100)
2023-08-28 17:50:47 +02:00
Chocobozzz
6b44f0b03c
Publish new version of peertube runner 2023-08-28 17:50:24 +02:00
Chocobozzz
9f4bdf3915
Add Guadeloupean language support 2023-08-28 17:11:27 +02:00
Chocobozzz
fe1e3535fd
Ping runners on job abort/error 2023-08-28 16:59:45 +02:00
Chocobozzz
6a85ec0480
Also handle SIGTERM to cleanup jobs 2023-08-28 16:52:08 +02:00
Chocobozzz
e23b95a901
Fix loading spinner displayed forever on chrome 2023-08-28 16:42:32 +02:00
Chocobozzz
8ed4b82346
Fix tests build 2023-08-28 16:42:32 +02:00
Alejandro
d6aeed4359 Corrected storage tmp location 2023-08-28 16:20:36 +02:00
Chocobozzz
77b70702d2
Add video chapters support 2023-08-28 16:17:31 +02:00
Chocobozzz
7113f32a87
Fix build 2023-08-21 15:55:54 +02:00
Chocobozzz
4d3ea87486
More robust about page
Don't throw if we can't find a category or a language
Can happen if the instance configuration contains a category/language
that has been deleted by a plugin for example
2023-08-21 15:32:33 +02:00
Chocobozzz
ab5f1356b9
Try to fix github ci 2023-08-21 15:04:33 +02:00
Chocobozzz
0d87602a20
Optimize update host script 2023-08-18 14:21:04 +02:00
Chocobozzz
273d57023b
Update translations 2023-08-18 14:12:32 +02:00
Chocobozzz
a4a8ccdfb6
Merge remote-tracking branch 'weblate/develop' into develop 2023-08-18 13:44:29 +02:00
Chocobozzz
c74dc602a6
Simplify table pagination footer 2023-08-18 13:43:59 +02:00
Chocobozzz
863ef63805
Fix typo 2023-08-18 13:43:55 +02:00
GunChleoc
f0e7993e46 Translated using Weblate (Gaelic)
Currently translated at 96.2% (2155 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-08-18 12:26:38 +02:00
Txopi
7c827e0b1a Translated using Weblate (Basque)
Currently translated at 38.7% (867 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-08-18 12:26:38 +02:00
GunChleoc
c6660368e9 Translated using Weblate (Gaelic)
Currently translated at 94.3% (2113 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-08-18 12:26:38 +02:00
GunChleoc
7f8601bc5d Translated using Weblate (Gaelic)
Currently translated at 92.5% (2074 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-08-18 12:26:38 +02:00
GunChleoc
ea4ae0abdc Translated using Weblate (Gaelic)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/gd/
2023-08-18 12:26:38 +02:00
GunChleoc
6fd18713a5 Translated using Weblate (Gaelic)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/gd/
2023-08-18 12:26:38 +02:00
GunChleoc
49eda08643 Translated using Weblate (Gaelic)
Currently translated at 91.5% (2050 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/gd/
2023-08-18 12:26:38 +02:00
Txopi
d952a2b787 Translated using Weblate (Basque)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/eu/
2023-08-18 12:26:38 +02:00
Txopi
89cc743dd5 Translated using Weblate (Basque)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/eu/
2023-08-18 12:26:38 +02:00
jinubook
fe86ac023a Translated using Weblate (Korean)
Currently translated at 9.5% (214 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ko/
2023-08-18 12:26:38 +02:00
Mamiako Pavel
3ca4ccc9ad Translated using Weblate (Russian)
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-08-18 12:26:38 +02:00
Александр
7a6b5776e4 Translated using Weblate (Russian)
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-08-18 12:26:38 +02:00
Renne Rocha
3da9cb2aa8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 63.2% (1416 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/pt_BR/
2023-08-18 12:26:37 +02:00
Milo Ivir
5eb669472e Translated using Weblate (Croatian)
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-08-18 12:26:37 +02:00
Timur Seber
b1e9f22815 Translated using Weblate (Tatar)
Currently translated at 1.4% (32 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/tt/
2023-08-18 12:26:37 +02:00
Jeff Huang
b591c569ec Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-08-18 12:26:37 +02:00
Hồ Nhất Duy
0112fa45ad Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-08-18 12:26:37 +02:00
Ihor Hordiichuk
cd3d5c22dd Translated using Weblate (Ukrainian)
Currently translated at 98.4% (2206 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-08-18 12:26:37 +02:00
Timur Seber
e65135150a Added translation using Weblate (Tatar) 2023-08-18 12:26:37 +02:00
Александр
909fac516c Translated using Weblate (Russian)
Currently translated at 100.0% (2240 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-08-18 12:26:37 +02:00
Txopi
ce2e0ae23d Translated using Weblate (Basque)
Currently translated at 37.2% (835 of 2240 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/eu/
2023-08-18 12:26:37 +02:00
Chocobozzz
cb909ab38a
Fix security.txt test 2023-08-18 11:54:55 +02:00
Chocobozzz
64cb55fcb1
Correctly handle optional replay setting 2023-08-18 11:52:12 +02:00
Chocobozzz
18570bee99
Add unset originallyPublishedAt test 2023-08-18 11:50:36 +02:00
Chocobozzz
18987248f6
Add test without replay settings object 2023-08-18 11:45:16 +02:00
Chocobozzz
7ace48819e
Add ability to reset originallyPublishedAt 2023-08-18 11:40:54 +02:00
Chocobozzz
ca589b42f1
Fix button router link
Using the default one assigns the directive to the host, where we just
want to put it inside the `my-button` component
2023-08-18 11:09:34 +02:00
Chocobozzz
c925e99ca4
Fix helper tests 2023-08-18 10:52:53 +02:00
Chocobozzz
90b84bd4bb
Fix live replay setting breaking change 2023-08-18 10:49:33 +02:00
Chocobozzz
5f79f37d10
Remove useless information 2023-08-18 10:39:49 +02:00
Chocobozzz
822872aacd
Don't display admin email in security.txt 2023-08-18 10:35:45 +02:00
Chocobozzz
3ff44b67ea
Fix plugin global path error log 2023-08-18 10:19:43 +02:00
Chocobozzz
9c63644b2d
Fix peertube helpers tsx tests 2023-08-18 10:18:56 +02:00
Seth Falco
2055962c84 fix: handle git installation of ffmpeg 2023-08-18 10:17:16 +02:00
Chocobozzz
8e4fba97b2
Automatically adapt player ratio 2023-08-18 09:48:45 +02:00
Chocobozzz
276f5fa24f
Fix peertube runner build 2023-08-18 07:54:31 +02:00
Chocobozzz
869c5c7b5c
Update openapi version 2023-08-17 15:18:27 +02:00
Chocobozzz
5ab73a4570
Improve plugin guide 2023-08-17 15:18:27 +02:00
Yehuda Deutsch
f7882ca3eb Switch from debian bullseye to bookworm 2023-08-17 15:18:21 +02:00
Chocobozzz
a5bde7ad60
Fix benchmark script 2023-08-17 15:03:27 +02:00
Chocobozzz
23092139a6
Better abuse style of removed videos 2023-08-17 14:34:49 +02:00
Chocobozzz
c5f8dc0533
Correctly truncate HTML
We can because we don't use the video truncated description since v5.0
2023-08-17 14:34:49 +02:00
Chocobozzz
e4f82eaa8b
Remove invalid timeout 2023-08-17 14:34:49 +02:00
John Livingston
e6c12444aa Enhance registerClientRoute documentation:
Adding the path on which routes created with registerClientRoute are
available.
2023-08-17 13:38:26 +02:00
Chocobozzz
cb78deba47
Fix broken links 2023-08-17 09:46:24 +02:00
Chocobozzz
0632cdda04
Fix build 2023-08-17 09:24:45 +02:00
Chocobozzz
c380e39285
Merge branch 'feature/esm-and-nx' into develop 2023-08-17 08:59:21 +02:00
Chocobozzz
3a4992633e
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge
conflicts, but it's a major step forward:

 * Server can be faster at startup because imports() are async and we can
   easily lazy import big modules
 * Angular doesn't seem to support ES import (with .js extension), so we
   had to correctly organize peertube into a monorepo:
    * Use yarn workspace feature
    * Use typescript reference projects for dependencies
    * Shared projects have been moved into "packages", each one is now a
      node module (with a dedicated package.json/tsconfig.json)
    * server/tools have been moved into apps/ and is now a dedicated app
      bundled and published on NPM so users don't have to build peertube
      cli tools manually
    * server/tests have been moved into packages/ so we don't compile
      them every time we want to run the server
 * Use isolatedModule option:
   * Had to move from const enum to const
     (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums)
   * Had to explictely specify "type" imports when used in decorators
 * Prefer tsx (that uses esbuild under the hood) instead of ts-node to
   load typescript files (tests with mocha or scripts):
     * To reduce test complexity as esbuild doesn't support decorator
       metadata, we only test server files that do not import server
       models
     * We still build tests files into js files for a faster CI
 * Remove unmaintained peertube CLI import script
 * Removed some barrels to speed up execution (less imports)
2023-08-11 15:02:33 +02:00
Chocobozzz
a8ca6190fb
Fix youtube-dl tests 2023-08-09 11:09:06 +02:00
Chocobozzz
04d1da5621
Update translations 2023-07-31 10:03:03 +02:00
Sveinn í Felli
ad0515e962 Translated using Weblate (Icelandic)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/is/
2023-07-31 09:36:19 +02:00
Shun Sakai
f060fb7890 Translated using Weblate (Japanese)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/ja/
2023-07-31 09:36:19 +02:00
Blood Axe
a190f53b07 Translated using Weblate (Norwegian Bokmål)
Currently translated at 83.7% (1858 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/nb_NO/
2023-07-31 09:36:19 +02:00
Blood Axe
cf4aa3b50d Translated using Weblate (Norwegian Bokmål)
Currently translated at 77.6% (1723 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/nb_NO/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
b77baa8dd7 Translated using Weblate (Ukrainian)
Currently translated at 98.5% (2186 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
53e765aa43 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/uk/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
caf5fddb63 Translated using Weblate (Ukrainian)
Currently translated at 98.2% (2181 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
c333fcd4c1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/uk/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
3264b91797 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (269 of 269 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/uk/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
71e3d66ad1 Translated using Weblate (Ukrainian)
Currently translated at 98.2% (2181 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-31 09:36:19 +02:00
T.S
335bf9d159 Translated using Weblate (Japanese)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-07-31 09:36:19 +02:00
DignifiedSilence
eab39eeaa2 Translated using Weblate (Japanese)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-07-31 09:36:19 +02:00
DignifiedSilence
43900e44a5 Translated using Weblate (Japanese)
Currently translated at 99.9% (2218 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-07-31 09:36:19 +02:00
Sveinn í Felli
8eb672b901 Translated using Weblate (Icelandic)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/is/
2023-07-31 09:36:19 +02:00
Hannes Ylä-Jääski
87554129c1 Translated using Weblate (Finnish)
Currently translated at 100.0% (141 of 141 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/fi/
2023-07-31 09:36:19 +02:00
Hannes Ylä-Jääski
7c17c6e088 Translated using Weblate (Finnish)
Currently translated at 100.0% (271 of 271 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/fi/
2023-07-31 09:36:19 +02:00
Hannes Ylä-Jääski
e5ac2bd89d Translated using Weblate (Finnish)
Currently translated at 93.8% (2082 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fi/
2023-07-31 09:36:19 +02:00
Александр
ce551c05ef Translated using Weblate (Russian)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-07-31 09:36:19 +02:00
Milo Ivir
64c25db21c Translated using Weblate (Croatian)
Currently translated at 100.0% (269 of 269 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/hr/
2023-07-31 09:36:19 +02:00
Александр
44a3c5e60b Translated using Weblate (Russian)
Currently translated at 99.0% (2199 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-07-31 09:36:19 +02:00
Milo Ivir
e28d3fd8cf Translated using Weblate (Croatian)
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-31 09:36:19 +02:00
Milo Ivir
dfa93a67c4 Translated using Weblate (Croatian)
Currently translated at 100.0% (140 of 140 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/hr/
2023-07-31 09:36:19 +02:00
Jeff Huang
3bde8546cf Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2219 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-07-31 09:36:19 +02:00
Milo Ivir
37371739ab Translated using Weblate (Croatian)
Currently translated at 99.9% (2217 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-31 09:36:19 +02:00
Ihor Hordiichuk
29594b0e7a Translated using Weblate (Ukrainian)
Currently translated at 98.2% (2181 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-31 09:36:19 +02:00
Milo Ivir
afdc22fb24 Translated using Weblate (Croatian)
Currently translated at 99.8% (2216 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-31 09:36:19 +02:00
Milo Ivir
d8c0ffc2b5 Translated using Weblate (Croatian)
Currently translated at 100.0% (269 of 269 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/hr/
2023-07-31 09:36:19 +02:00
Milo Ivir
a902f3afcf Translated using Weblate (Croatian)
Currently translated at 99.7% (2213 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-31 09:36:19 +02:00
Milo Ivir
533a4a61f4 Translated using Weblate (Croatian)
Currently translated at 99.0% (2197 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-31 09:36:19 +02:00
Payman Moghadam
0bfa26f9cf Translated using Weblate (Persian)
Currently translated at 98.9% (2196 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-31 09:36:18 +02:00
Ihor Hordiichuk
9b7b784083 Translated using Weblate (Ukrainian)
Currently translated at 97.5% (2165 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-31 09:36:18 +02:00
Payman Moghadam
ab84f2802d Translated using Weblate (Persian)
Currently translated at 98.9% (2196 of 2219 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-31 09:36:18 +02:00
Chocobozzz
3229fcf704
More robust logs tests 2023-07-31 09:35:48 +02:00
Chocobozzz
5e1ced7067
Fix live tests 2023-07-31 09:31:28 +02:00
Chocobozzz
257df4cb56
Remove deprecated "views" from live video event 2023-07-28 16:35:57 +02:00
Chocobozzz
982edf32ae
Remove deprecated video query filter 2023-07-28 16:33:12 +02:00
Chocobozzz
ce8d0b5aae
Remove deprecated scheduler 2023-07-28 16:22:27 +02:00
Chocobozzz
b203a25e1f
Keep s3 commands simple
As s3 implementation between s3 providers can be different
2023-07-28 16:21:15 +02:00
Chocobozzz
eeb838faf2
currentTime is now required 2023-07-28 16:17:37 +02:00
Chocobozzz
74c8d5bf2d
Refactor enableTranscoding command helpers 2023-07-28 16:06:49 +02:00
Chocobozzz
e390107e5a
Fix add to playlist button width 2023-07-28 15:55:49 +02:00
Chocobozzz
f9ac050a35
Remove unnecessary workarounds
Has been fixed upstream
2023-07-28 15:46:14 +02:00
Chocobozzz
3193ac2c3b
Refactor a little bit nsfwPolicyToParam 2023-07-28 15:37:22 +02:00
Chocobozzz
65bb29c6d3
Remove unnecesary fixme/todo 2023-07-28 15:20:49 +02:00
Chocobozzz
2bfc8ce3d0
Remove unnecessary cast 2023-07-28 11:41:17 +02:00
Chocobozzz
f932957b2e
Remove banner/avatar fields from channel/account
Deprecated since 4.2
2023-07-28 11:41:14 +02:00
Chocobozzz
89aa333110
Add ability to force transcoding 2023-07-28 11:09:03 +02:00
Chocobozzz
ac8f81e373
Reduce hls.js not supported log
Happens often on iOS
2023-07-28 09:18:12 +02:00
mira.bat
f862be2749
Add an option to sign federated fetches for mastodon compatibility (#5898)
* Fix player error modal

Not hidden when we change the video

* Correctly dispose player components

* Sign cross-server fetch requests for mastodon AUTHORIZED_FETCH compatibilty

* Add a remote fetch sign configuration knob

* Federated fetches refactoring

---------

Co-authored-by: Chocobozzz <me@florianbigard.com>
Co-authored-by: ira <ira@foxgirl.space>
2023-07-27 17:01:15 +02:00
Chocobozzz
787d822cd4
Rephrase emailer conflict error messages 2023-07-27 16:41:35 +02:00
Chocobozzz
809fecf2b4
Correctly dispose player components 2023-07-27 14:49:58 +02:00
Chocobozzz
39c0ceee8b
Fix player error modal
Not hidden when we change the video
2023-07-27 14:44:34 +02:00
Chocobozzz
9dfbf73576
Increase rate limits for benchmark 2023-07-27 14:18:59 +02:00
Chocobozzz
f18003d0ac
Improve runner management
* Add ability to remove runner jobs
 * Add runner job state quick filter
 * Merge registration tokens and runners tables in the same page
 * Add copy button to copy registration token
2023-07-27 14:17:12 +02:00
Chocobozzz
f5af5feb5a
Use built in toc doc
As we mainly use this file on https://docs.joinpeertube.org/contribute/plugins
2023-07-26 11:47:00 +02:00
Chocobozzz
ec3228cae7
Fix playlist owner font size 2023-07-26 11:03:21 +02:00
Chocobozzz
17522af1e0
Use typed pick 2023-07-26 10:49:32 +02:00
Chocobozzz
69e3f2049f
Fix invalid short uuid conversion
Avoid "TypeError: Expected a string but received a null" error
2023-07-26 10:48:30 +02:00
Chocobozzz
3ffff82e87
Truncate html/og/card HTML description tags 2023-07-26 10:19:51 +02:00
Chocobozzz
d7c3670945
Fix lint 2023-07-26 10:08:24 +02:00
Chocobozzz
053ed7f5e6
Update code contributors 2023-07-26 09:49:53 +02:00
Chocobozzz
22e7ffc781
Fix check params tests 2023-07-26 09:42:44 +02:00
Chocobozzz
93fd6f3b18
Fix fk error when generating storyboard 2023-07-26 09:25:21 +02:00
Chocobozzz
89b9eab5a7
Add more logs to debug oauth-client error 2023-07-26 09:25:10 +02:00
Chocobozzz
97583d0023
Add more rate limits 2023-07-26 08:37:50 +02:00
Chocobozzz
9901c8d690
Add video file update hook tests 2023-07-25 15:17:58 +02:00
Chocobozzz
3b46eec8ae
Remove unused param 2023-07-25 14:26:12 +02:00
Chocobozzz
f42dd5524b
Add more context to request error 2023-07-25 14:21:01 +02:00
Chocobozzz
f42fcb4b58
Implement video file replacement in client 2023-07-25 11:53:08 +02:00
Chocobozzz
12dc3a942a
Implement replace file in server side 2023-07-21 17:38:13 +02:00
Chocobozzz
c6867725fb
Add p2p info to metrics 2023-07-21 11:42:52 +02:00
Chocobozzz
b63c607b92
Fix updating P2P setting 2023-07-21 11:07:49 +02:00
Chocobozzz
305facdfab
Add peers number and p2p enabled label to metrics 2023-07-20 12:06:39 +02:00
Chocobozzz
4e5da193d0
Keep old docker path for web videos
Avoid breaking existing peertube instances on upgrade
2023-07-20 11:26:33 +02:00
Chocobozzz
8a9d247105
Fix "undefined" in stats card 2023-07-20 11:18:47 +02:00
Chocobozzz
4ddf488ab5
Improve player settings menu style 2023-07-20 10:53:22 +02:00
Chocobozzz
c8defc41ee
Fix max settings panel height 2023-07-20 10:26:14 +02:00
Chocobozzz
8ece9c8ca0
Improve recommended videos without video tags 2023-07-19 13:24:31 +02:00
Chocobozzz
4f8b623668
Add missing storyboard directory to docker 2023-07-19 11:42:00 +02:00
Chocobozzz
d430862f00
Force ltr on code inputs 2023-07-19 11:22:05 +02:00
Chocobozzz
15c2303489
More robust runner socket test 2023-07-19 10:43:12 +02:00
Chocobozzz
bfd01f289d
Fix player metrics 2023-07-19 10:20:01 +02:00
Chocobozzz
6b745df087
Try to fix CI test 2023-07-17 14:34:44 +02:00
Chocobozzz
c6a3445360
Fix lint 2023-07-17 14:17:18 +02:00
Chocobozzz
4212a107d4
Update translations 2023-07-17 11:50:58 +02:00
Blood Axe
b0ac4b2438 Translated using Weblate (Norwegian Bokmål)
Currently translated at 77.0% (1734 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/nb_NO/
2023-07-17 11:46:42 +02:00
Vodoyo Kamal
8a0ee81535 Translated using Weblate (Bengali)
Currently translated at 8.1% (143 of 1748 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/bn/
2023-07-17 11:46:42 +02:00
Ewout van Mansom
4dcc1f4c9f Translated using Weblate (Dutch)
Currently translated at 94.9% (2137 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/nl/
2023-07-17 11:46:42 +02:00
Blood Axe
1464f3bd1c Translated using Weblate (Norwegian Bokmål)
Currently translated at 70.5% (1587 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/nb_NO/
2023-07-17 11:46:42 +02:00
Blood Axe
82a5bbf509 Translated using Weblate (Norwegian Bokmål)
Currently translated at 82.9% (112 of 135 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/nb_NO/
2023-07-17 11:46:42 +02:00
Branislav Pavelka
39802e9ec4 Translated using Weblate (Slovak)
Currently translated at 2.4% (54 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-07-17 11:46:42 +02:00
Victor Hampel
0341f8445a Translated using Weblate (German)
Currently translated at 100.0% (270 of 270 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/de/
2023-07-17 11:46:42 +02:00
Phongpanot
a65c450a3b Translated using Weblate (Thai)
Currently translated at 62.5% (1408 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/th/
2023-07-17 11:46:42 +02:00
Phongpanot
e2991217a3 Translated using Weblate (Thai)
Currently translated at 62.5% (1408 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/th/
2023-07-17 11:46:42 +02:00
Payman Moghadam
7d1d5514c2 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:42 +02:00
Hồ Nhất Duy
a88684e0df Translated using Weblate (Vietnamese)
Currently translated at 100.0% (135 of 135 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/vi/
2023-07-17 11:46:42 +02:00
Hồ Nhất Duy
2a21ecc873 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/vi/
2023-07-17 11:46:42 +02:00
Branislav Pavelka
d3b0db9168 Translated using Weblate (Slovak)
Currently translated at 1.6% (38 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/sk/
2023-07-17 11:46:42 +02:00
Payman Moghadam
82a3277db7 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:42 +02:00
Jiri Podhorecky
b7b50dfa76 Translated using Weblate (Czech)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/cs/
2023-07-17 11:46:42 +02:00
Milo Ivir
47b89723dd Translated using Weblate (Croatian)
Currently translated at 100.0% (268 of 268 strings)

Translation: PeerTube/server
Translate-URL: https://weblate.framasoft.org/projects/peertube/server/hr/
2023-07-17 11:46:42 +02:00
Milo Ivir
ce65d401dd Translated using Weblate (Croatian)
Currently translated at 99.3% (2236 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/hr/
2023-07-17 11:46:42 +02:00
DignifiedSilence
87421e87a9 Translated using Weblate (Japanese)
Currently translated at 100.0% (135 of 135 strings)

Translation: PeerTube/player
Translate-URL: https://weblate.framasoft.org/projects/peertube/player/ja/
2023-07-17 11:46:42 +02:00
DignifiedSilence
4ab9816215 Translated using Weblate (Japanese)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-07-17 11:46:41 +02:00
T.S
b6ac52d52c Translated using Weblate (Japanese)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ja/
2023-07-17 11:46:41 +02:00
Payman Moghadam
ec731e21f4 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Payman Moghadam
87c8a55284 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Payman Moghadam
3b9f845145 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Payman Moghadam
ec2922b660 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Payman Moghadam
6078c0e4e9 Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Jeff Huang
2d78af0f68 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/zh_Hant/
2023-07-17 11:46:41 +02:00
Payman Moghadam
ed2b8f127c Translated using Weblate (Persian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/fa/
2023-07-17 11:46:41 +02:00
Ihor Hordiichuk
39d58998c4 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (2203 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/uk/
2023-07-17 11:46:41 +02:00
Александр
1cfded4f14 Translated using Weblate (Russian)
Currently translated at 100.0% (2250 of 2250 strings)

Translation: PeerTube/angular
Translate-URL: https://weblate.framasoft.org/projects/peertube/angular/ru/
2023-07-17 11:46:41 +02:00
Chocobozzz
d0b7d66f58
Fix password E2E tests 2023-07-17 11:46:24 +02:00
Chocobozzz
9a72e4fe9e
Improve settings menu label handler 2023-07-17 11:31:46 +02:00
Chocobozzz
e29221f855
Fix e2e tests 2023-07-17 11:31:46 +02:00
Chocobozzz
9684bc959e
Fix anonymous autoplay 2023-07-17 11:31:46 +02:00
Chocobozzz
45ec48b2b1
Don't update opengraph in angular
We already set these tags in the server
2023-07-17 11:31:46 +02:00
Chocobozzz
28dd2f14f5
Some player fixes on Android, Safari and iOS 2023-07-17 11:31:46 +02:00
Chocobozzz
930e1b939a
Fix HLS player on mobile 2023-07-17 11:31:46 +02:00
Chocobozzz
9bb541bec7
Round HTTP/P2P network stats 2023-07-17 11:31:46 +02:00
Chocobozzz
9bc85bd2f8
Prevent multiple sha requests 2023-07-17 11:31:46 +02:00
Chocobozzz
9a26d00e5e
Add nginx comment for webseed redirection 2023-07-17 11:31:46 +02:00
Wicklow
cbe06f779f
Add e2e tests for password protected videos (#5860) 2023-07-17 11:31:42 +02:00
Jackson Chen
260242decd update third party link to docs 2023-07-17 11:30:45 +02:00
Chocobozzz
288e1d37e9
Fix lint 2023-07-12 13:39:37 +02:00
Chocobozzz
5c34189aa9
Fix prune storage test 2023-07-12 11:32:12 +02:00
Chocobozzz
c5ad375a2c
Use web-videos for webseed redirection 2023-07-12 11:26:01 +02:00
Chocobozzz
d874522774
Avoid update remote runner error 2023-07-12 11:14:59 +02:00
Chocobozzz
d959b763f0
Avoid duplicate runner names 2023-07-12 10:56:07 +02:00
Chocobozzz
88cde4392a
Merge branch 'release/5.2.0' into develop 2023-07-12 10:37:59 +02:00
Chocobozzz
97f57e928f
Add custom db port when upgrading peertube 2023-07-11 13:43:41 +02:00
Chocobozzz
34555bebf8
Migrate from webseed to web-videos 2023-07-11 11:39:59 +02:00
Chocobozzz
d732ec7b46
Rename "videos" config to "web-videos" 2023-07-11 11:23:51 +02:00
Chocobozzz
76824f522a
Reword runner registration 2023-07-11 10:10:51 +02:00
Chocobozzz
c57ad141a9
Rename webtorrent config to web_videos 2023-07-11 09:52:14 +02:00
Chocobozzz
784e2ad5c3
Prefer web videos in favour of webtorrent 2023-07-11 09:21:13 +02:00
Chocobozzz
c3030e944a
Fix build 2023-07-10 16:41:08 +02:00
Chocobozzz
63e2f087c3
Merge branch 'feature/remove-webtorrent' into develop 2023-07-10 16:13:22 +02:00
Chocobozzz
8953f055c8
Rename player embed api 2023-07-10 16:08:53 +02:00
Chocobozzz
a1bd2b77d9
Remove webtorrent support from client 2023-07-10 16:08:28 +02:00
Chocobozzz
83b42f5a32
Add note for peertube runner dependencies 2023-07-06 16:59:20 +02:00
Chocobozzz
8ef866071f
Fix fetching storyboard of password protected video 2023-06-29 14:22:13 +02:00
Chocobozzz
9cd06903f4
Fix HLS playlist generation with 0 duration length 2023-06-29 14:20:03 +02:00
Chocobozzz
a287136427
Fix migration conflict 2023-06-29 13:52:24 +02:00
Chocobozzz
6bd160a68d
Fix 400 error on resumable re-upload 2023-06-29 11:35:25 +02:00
q_h
926c3f2b37
Fix the cleanup after a failed upload (#5840)
* Fix the cleanup after a failed upload

* Update tests

* Update tests
2023-06-29 10:38:37 +02:00
Chocobozzz
9fe86c2c9b
Update runner version 2023-06-29 10:19:55 +02:00
Chocobozzz
d68b88bac4
Prevent stalled jobs 2023-06-29 10:19:55 +02:00
Chocobozzz
bc3918b2ae
Shuffle servers when checking available jobs
To not favour a specific instance
2023-06-29 10:19:55 +02:00
Chocobozzz
19aeb64b25
Better channel deletion message 2023-06-29 10:19:55 +02:00
Chocobozzz
d961735d5d
Fix prune storage tests 2023-06-29 10:19:55 +02:00
Chocobozzz
180d8f297e
More robust wait transcoding checkbox display 2023-06-29 10:19:55 +02:00
Chocobozzz
17ad0e8428
Fix regenerate thumbnail test 2023-06-29 10:19:55 +02:00
Chocobozzz
cf069671f4
Use promise cache to load remote thumbnails 2023-06-29 10:19:55 +02:00
Chocobozzz
2b5dfa2fe0
Fix adding element in playlists 2023-06-29 10:19:55 +02:00
Chocobozzz
7a30349748
Fix migration conflict 2023-06-29 10:19:55 +02:00
Chocobozzz
53d4db2a8a
Fix playlist thumbnail generation 2023-06-29 10:19:54 +02:00
Chocobozzz
109d4a7f01
Add thumbnail disk database migration 2023-06-29 10:19:33 +02:00
Chocobozzz
89becbcb37
Add missing playbackRate URL param doc 2023-06-29 10:19:33 +02:00
Chocobozzz
bafaba0bcd
Support lazy download of remote video miniatures 2023-06-29 10:19:33 +02:00
Chocobozzz
f162d32da0
Support lazy download thumbnails 2023-06-29 10:19:33 +02:00
Chocobozzz
a673d9e848
Fix storyboard tests 2023-06-29 10:19:07 +02:00
Chocobozzz
ff75ba7160
Also replace base url of pre signed s3 url 2023-06-29 10:19:07 +02:00
Chocobozzz
c37e305342
Fix CI tests 2023-06-29 10:19:05 +02:00
Chocobozzz
881958d179
Correctly download files from S3
Use pre signed URLs to inject content disposition header
2023-06-29 10:18:21 +02:00
Chocobozzz
1c9dc98c27
Lock video files when generating storyboard 2023-06-29 10:18:21 +02:00
Chocobozzz
d299afeb2c
Fix lint 2023-06-29 10:18:20 +02:00
Chocobozzz
7f7e9d4e90
Handle correctly formatted AP attributedTo 2023-06-29 10:18:00 +02:00
Chocobozzz
cefe22cf7c
Fetch remote AP objects if only id is specified 2023-06-29 10:18:00 +02:00
Chocobozzz
f987425bd1
Fix thumbnails tests 2023-06-29 10:18:00 +02:00
Chocobozzz
d896fef7e2
Refactor video formatter 2023-06-29 10:18:00 +02:00
Chocobozzz
638a295021
Support storyboards in embed 2023-06-29 10:17:59 +02:00
Chocobozzz
52807a075f
Fix storyboard on firefox 2023-06-29 10:16:57 +02:00
Chocobozzz
b7f946892b
Simpler thumbnail generation 2023-06-29 10:16:57 +02:00
Chocobozzz
318aa9c422
Delete storyboard file on video deletion 2023-06-29 10:16:57 +02:00
Chocobozzz
9c5cc50133
Add script to generate storyboards 2023-06-29 10:16:57 +02:00
Chocobozzz
d8f39b126d
Add storyboard support 2023-06-29 10:16:55 +02:00
Chocobozzz
1fb7d09422
Don't cache upload after video deletion 2023-06-29 09:49:06 +02:00
Chocobozzz
866c5f667d
Simplify ICU in components 2023-06-29 09:49:06 +02:00
Wicklow
40346ead2b
Feature/password protected videos (#5836)
* Add server endpoints

* Refactoring test suites

* Update server and add openapi documentation

* fix compliation and tests

* upload/import password protected video on client

* add server error code

* Add video password to update resolver

* add custom message when sharing pw protected video

* improve confirm component

* Add new alert in component

* Add ability to watch protected video on client

* Cannot have password protected replay privacy

* Add migration

* Add tests

* update after review

* Update check params tests

* Add live videos test

* Add more filter test

* Update static file privacy test

* Update object storage tests

* Add test on feeds

* Add missing word

* Fix tests

* Fix tests on live videos

* add embed support on password protected videos

* fix style

* Correcting data leaks

* Unable to add password protected privacy on replay

* Updated code based on review comments

* fix validator and command

* Updated code based on review comments
2023-06-29 09:48:55 +02:00
2746 changed files with 174143 additions and 150004 deletions

View File

@ -1,5 +1,6 @@
{ {
"extends": "standard-with-typescript", "extends": "standard-with-typescript",
"root": true,
"rules": { "rules": {
"eol-last": [ "eol-last": [
"error", "error",
@ -126,18 +127,20 @@
] ]
}, },
"ignorePatterns": [ "ignorePatterns": [
"node_modules/", "node_modules",
"server/tests/fixtures" "packages/tests/fixtures",
"apps/**/dist",
"packages/**/dist",
"server/dist",
"packages/types-generator/tests",
"*.js",
"/client",
"/dist"
], ],
"parserOptions": { "parserOptions": {
"EXPERIMENTAL_useSourceOfProjectReferenceRedirect": true,
"project": [ "project": [
"./tsconfig.json", "./tsconfig.eslint.json"
"./shared/tsconfig.json", ],
"./scripts/tsconfig.json", "EXPERIMENTAL_useSourceOfProjectReferenceRedirect": true
"./server/tsconfig.json",
"./server/tools/tsconfig.json",
"./packages/peertube-runner/tsconfig.json"
]
} }
} }

View File

@ -53,13 +53,25 @@ interested in, user interface, design, decentralized architecture...
You can help to write the documentation of the REST API, code, architecture, You can help to write the documentation of the REST API, code, architecture,
demonstrations. demonstrations.
For the REST API you can see the documentation in [/support/doc/api](https://github.com/Chocobozzz/PeerTube/tree/develop/support/doc/api) directory. ### User documentation
Then, you can just open the `openapi.yaml` file in a special editor like [http://editor.swagger.io/](http://editor.swagger.io/) to easily see and edit the documentation. You can also use [redoc-cli](https://github.com/Redocly/redoc/blob/master/cli/README.md) and run `redoc-cli serve --watch support/doc/api/openapi.yaml` to see the final result.
The official user documentation is available on https://docs.joinpeertube.org/
You can update it by writing markdown files in the following repository: https://framagit.org/framasoft/peertube/documentation/
### REST API documentation
The [REST API documentation](https://docs.joinpeertube.org/api-rest-reference.html) is generated from `support/doc/api/openapi.yaml` file.
To quickly get a preview of your changes, you can generate the documentation *on the fly* using the following command:
```
npx @redocly/cli preview-docs ./support/doc/api/openapi.yaml
```
Some hints: Some hints:
* Routes are defined in [/server/controllers/](https://github.com/Chocobozzz/PeerTube/tree/develop/server/controllers) directory * Routes are defined in [/server/core/controllers/](https://github.com/Chocobozzz/PeerTube/tree/develop/server/core/controllers) directory
* Parameters validators are defined in [/server/middlewares/validators](https://github.com/Chocobozzz/PeerTube/tree/develop/server/middlewares/validators) directory * Parameters validators are defined in [/server/core/middlewares/validators](https://github.com/Chocobozzz/PeerTube/tree/develop/server/core/middlewares/validators) directory
* Models sent/received by the controllers are defined in [/shared/models](https://github.com/Chocobozzz/PeerTube/tree/develop/shared/models) directory * Models sent/received by the controllers are defined in [/packages/models](https://github.com/Chocobozzz/PeerTube/tree/develop/packages/models) directory
## Improve the website ## Improve the website
@ -242,15 +254,6 @@ To test emails with PeerTube:
* Run [mailslurper](http://mailslurper.com/) * Run [mailslurper](http://mailslurper.com/)
* Run PeerTube using mailslurper SMTP port: `NODE_CONFIG='{ "smtp": { "hostname": "localhost", "port": 2500, "tls": false } }' NODE_ENV=dev node dist/server` * Run PeerTube using mailslurper SMTP port: `NODE_CONFIG='{ "smtp": { "hostname": "localhost", "port": 2500, "tls": false } }' NODE_ENV=dev node dist/server`
### OpenAPI documentation
The [REST API documentation](https://docs.joinpeertube.org/api-rest-reference.html) is generated from `support/doc/api/openapi.yaml` file.
To quickly get a preview of your changes, you can generate the documentation *on the fly* using the following command:
```
npx @redocly/cli preview-docs ./support/doc/api/openapi.yaml
```
### Environment variables ### Environment variables
PeerTube can be configured using environment variables. PeerTube can be configured using environment variables.

View File

@ -32,4 +32,12 @@ runs:
- name: Install peertube runner dependencies - name: Install peertube runner dependencies
shell: bash shell: bash
run: cd packages/peertube-runner && yarn install --frozen-lockfile run: cd apps/peertube-runner && yarn install --frozen-lockfile
- name: Install peertube CLI dependencies
shell: bash
run: cd apps/peertube-cli && yarn install --frozen-lockfile
- name: Display PeerTube dependencies
shell: bash
run: ls -l node_modules/@peertube

View File

@ -35,13 +35,14 @@ jobs:
- uses: './.github/actions/reusable-prepare-peertube-build' - uses: './.github/actions/reusable-prepare-peertube-build'
with: with:
node-version: '16.x' node-version: '18.x'
- uses: './.github/actions/reusable-prepare-peertube-run' - uses: './.github/actions/reusable-prepare-peertube-run'
- name: Build - name: Build
run: | run: |
startClient=`date +%s` startClient=`date +%s`
npm run build:server
npm run build:client npm run build:client
endClient=`date +%s` endClient=`date +%s`
clientBuildTime=$((endClient-startClient)) clientBuildTime=$((endClient-startClient))
@ -71,7 +72,7 @@ jobs:
- name: Run benchmark - name: Run benchmark
run: | run: |
node dist/scripts/benchmark.js -o benchmark.json npm run benchmark-server -- -o benchmark.json
- name: Display result - name: Display result
run: | run: |

View File

@ -29,7 +29,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'javascript' ] language: [ 'javascript-typescript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support # Learn more about CodeQL language support at https://git.io/codeql-language-support
@ -39,7 +39,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v2
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
config-file: ./.github/workflows/codeql/codeql-config.yml config-file: ./.github/workflows/codeql/codeql-config.yml
@ -51,7 +51,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v1 uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@ -65,4 +65,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v2

View File

@ -1,4 +1,6 @@
name: "PeerTube CodeQL config" name: "PeerTube CodeQL config"
paths-ignore: paths-ignore:
- server/tests - packages/tests
- packages/server-commands
- packages/types-generator

View File

@ -24,8 +24,8 @@ jobs:
# FIXME: https://github.com/actions/checkout/issues/290 # FIXME: https://github.com/actions/checkout/issues/290
git fetch --force --tags git fetch --force --tags
one="{ \"file\": \"./support/docker/production/Dockerfile.bullseye\", \"ref\": \"develop\", \"tags\": \"chocobozzz/peertube:develop-bullseye\" }" one="{ \"file\": \"./support/docker/production/Dockerfile.bookworm\", \"ref\": \"develop\", \"tags\": \"chocobozzz/peertube:develop-bookworm\" }"
two="{ \"file\": \"./support/docker/production/Dockerfile.bullseye\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube:production-bullseye,chocobozzz/peertube:$(git describe --abbrev=0)-bullseye\" }" two="{ \"file\": \"./support/docker/production/Dockerfile.bookworm\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube:production-bookworm,chocobozzz/peertube:$(git describe --abbrev=0)-bookworm\" }"
three="{ \"file\": \"./support/docker/production/Dockerfile.nginx\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube-webserver:latest\" }" three="{ \"file\": \"./support/docker/production/Dockerfile.nginx\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube-webserver:latest\" }"
matrix="[$one,$two,$three]" matrix="[$one,$two,$three]"

View File

@ -18,7 +18,7 @@ jobs:
- uses: './.github/actions/reusable-prepare-peertube-build' - uses: './.github/actions/reusable-prepare-peertube-build'
with: with:
node-version: '16.x' node-version: '18.x'
- name: Build - name: Build
run: npm run nightly run: npm run nightly

View File

@ -22,7 +22,7 @@ jobs:
- uses: './.github/actions/reusable-prepare-peertube-build' - uses: './.github/actions/reusable-prepare-peertube-build'
with: with:
node-version: '16.x' node-version: '18.x'
- name: Angular bundlewatch - name: Angular bundlewatch
uses: jackyef/bundlewatch-gh-action@master uses: jackyef/bundlewatch-gh-action@master
@ -36,12 +36,12 @@ jobs:
run: | run: |
wget "https://github.com/boyter/scc/releases/download/v3.0.0/scc-3.0.0-x86_64-unknown-linux.zip" wget "https://github.com/boyter/scc/releases/download/v3.0.0/scc-3.0.0-x86_64-unknown-linux.zip"
unzip "scc-3.0.0-x86_64-unknown-linux.zip" unzip "scc-3.0.0-x86_64-unknown-linux.zip"
./scc --format=json --exclude-dir .git,node_modules,client/node_modules,client/dist,dist,yarn.lock,client/yarn.lock,client/src/locale,test1,test2,test3,client/src/assets/images,config,storage,server/tests/fixtures,support/openapi,.idea,.vscode,docker-volume,ffmpeg-3,ffmpeg-4 > ./scc.json ./scc --format=json --exclude-dir .git,node_modules,client/node_modules,client/dist,dist,yarn.lock,client/yarn.lock,client/src/locale,test1,test2,test3,client/src/assets/images,config,storage,packages/tests/fixtures,support/openapi,.idea,.vscode,docker-volume,ffmpeg-3,ffmpeg-4 > ./scc.json
- name: PeerTube client stats - name: PeerTube client stats
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
run: | run: |
node dist/scripts/client-build-stats.js > client-build-stats.json npm run client:build-stats > client-build-stats.json
- name: PeerTube client lighthouse report - name: PeerTube client lighthouse report
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'

View File

@ -46,6 +46,7 @@ jobs:
PGHOST: localhost PGHOST: localhost
NODE_PENDING_JOB_WAIT: 250 NODE_PENDING_JOB_WAIT: 250
ENABLE_OBJECT_STORAGE_TESTS: true ENABLE_OBJECT_STORAGE_TESTS: true
ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS: true
OBJECT_STORAGE_SCALEWAY_KEY_ID: ${{ secrets.OBJECT_STORAGE_SCALEWAY_KEY_ID }} OBJECT_STORAGE_SCALEWAY_KEY_ID: ${{ secrets.OBJECT_STORAGE_SCALEWAY_KEY_ID }}
OBJECT_STORAGE_SCALEWAY_ACCESS_KEY: ${{ secrets.OBJECT_STORAGE_SCALEWAY_ACCESS_KEY }} OBJECT_STORAGE_SCALEWAY_ACCESS_KEY: ${{ secrets.OBJECT_STORAGE_SCALEWAY_ACCESS_KEY }}
YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN: ${{ secrets.GITHUB_TOKEN }} YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -55,7 +56,7 @@ jobs:
- uses: './.github/actions/reusable-prepare-peertube-build' - uses: './.github/actions/reusable-prepare-peertube-build'
with: with:
node-version: '16.x' node-version: '18.x'
- uses: './.github/actions/reusable-prepare-peertube-run' - uses: './.github/actions/reusable-prepare-peertube-run'

17
.gitignore vendored
View File

@ -1,8 +1,8 @@
# NPM instalation # NPM instalation
/node_modules/ node_modules
/server/tools/node_modules
*npm-debug.log *npm-debug.log
yarn-error.log yarn-error.log
.yarn
# Testing # Testing
/test1/ /test1/
@ -11,8 +11,8 @@ yarn-error.log
/test4/ /test4/
/test5/ /test5/
/test6/ /test6/
/server/tests/fixtures/video_high_bitrate_1080p.mp4 /packages/tests/fixtures/video_high_bitrate_1080p.mp4
/server/tests/fixtures/video_59fps.mp4 /packages/tests/fixtures/video_59fps.mp4
# Production # Production
/storage /storage
@ -23,6 +23,7 @@ yarn-error.log
/ffmpeg-4/ /ffmpeg-4/
/thumbnails/ /thumbnails/
/torrents/ /torrents/
/web-videos/
/videos/ /videos/
/previews/ /previews/
/logs/ /logs/
@ -48,12 +49,14 @@ yarn-error.log
/*.tar.xz /*.tar.xz
/*.asc /*.asc
*.DS_Store *.DS_Store
/server/tools/import-mediacore.ts
/docker-volume/ /docker-volume/
/init.mp4 /init.mp4
# TypeScript # TypeScript
*.tsbuildinfo *.tsbuildinfo
# Packages # EsLint
/packages/types/dist/ .eslintcache
# Compiled output
dist

10
.mocharc.cjs Normal file
View File

@ -0,0 +1,10 @@
process.env.ESBK_TSCONFIG_PATH = './packages/tests/tsconfig.json'
module.exports = {
"node-option": [
"loader=tsx",
"no-warnings",
"conditions=peertube:tsx"
],
"timeout": 30000
}

View File

@ -1,5 +1,190 @@
# Changelog # Changelog
## v6.0.1
### IMPORTANT NOTES
* If you upgrade from PeerTube **< v6.0.0**, please follow v6.0.0 IMPORTANT NOTES
* We've made some modifications in v6.0.0 IMPORTANT NOTES, so if you upgrade from PeerTube v6.0.0:
* Ensure `location = /api/v1/videos/upload-resumable {` has been replaced by `location ~ ^/api/v1/videos/(upload-resumable|([^/]+/source/replace-resumable))$ {` in your nginx configuration
* Ensure you updated `storage.web_videos` configuration value to use `web-videos/` directory name
* Ensure your directory name on filesystem is the same as `storage.web_videos` configuration value: directory on filesystem must be renamed from `videos/` to `web-videos/` to represent the value of `storage.web_videos`
### Bug fixes
* Fix CPU going to 100% on odd cpu count
* Increase storyboard generation job TTL
* Add missing `generate-video-storyboard` job type in admin jobs list
* Regenerate storyboard after studio job
## v6.0.0
### IMPORTANT NOTES
We have many important notes in this release. We know it's a pain for sysadmin, but consider each one as a major step forward for PeerTube quality!
#### Sysadmins important notes
* Remove NodeJS 16 support (see https://nodejs.org/fr/blog/announcements/nodejs16-eol):
* Please upgrade to NodeJS 18 before upgrading PeerTube
* If you use NodeSource repository, you may have to migrate to their new repository: https://github.com/nodesource/distributions/wiki/How-to-migrate-to-the-new-repository
* Check in `production.yaml` that you use `127.0.0.1` instead of `localhost` for `listen.hostname`, `database.hostname` and `redis.hostname` as Node 18 favours IPv6 for `localhost` resolution
* Remove WebTorrent support in player:
* "WebTorrent videos" are renamed to "Web Video". The video format is the same, we just stop to use P2P for these videos
* There is no "Auto" quality anymore for Web Videos. The viewer has to explicitly choose the video resolution
* We still use P2P with the HLS player, which is the recommended transcoding format since several versions
* See https://github.com/Chocobozzz/PeerTube/issues/5465 for more information
* Configuration key that you must update in your `production.yaml` if not automatically done by your upgrade script:
* `storage.videos` must be **renamed** to `storage.web_videos`: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L151
* Configuration value of `storage.web_videos` must have the directory name to be **changed** from `videos/` to `web-videos/`: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L151
* Directory on filesystem must be **renamed** from `videos/` to `web-videos/` to represent the value of `storage.web_videos`
* Classic installation: `sudo -u peertube mv '/var/www/peertube/storage/videos/' '/var/www/peertube/storage/web-videos/'`
* Docker installation: `mv '/path-to-docker-installation/docker-volume/data/videos/' '/path-to-docker-installation/docker-volume/data/web-videos/'`
* `transcoding.webtorrent` must be **renamed** to `transcoding.web_videos`: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L532
* `object_storage.videos` must be **renamed** to `object_storage.web_videos`. The value of `object_storage.web_videos.bucket_name` doesn't need to be changed: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L223
* `storage.storyboards` must be **added**: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L157
* PeerTube Docker image now uses `bookworm`. `chocobozzz/peertube:production-bullseye` needs to be replaced by `chocobozzz/peertube:production-bookworm`
* Env configuration that your must update if you use Docker:
* `PEERTUBE_TRANSCODING_WEBTORRENT_ENABLED` must be **renamed** to `PEERTUBE_TRANSCODING_WEB_VIDEOS_ENABLED`
* `PEERTUBE_OBJECT_STORAGE_VIDEOS_BUCKET_NAME` must be **renamed** to `PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BUCKET_NAME`
* `PEERTUBE_OBJECT_STORAGE_VIDEOS_PREFIX` must be **renamed** to `PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_PREFIX`
* `PEERTUBE_OBJECT_STORAGE_VIDEOS_BASE_URL` must be **renamed** to `PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BASE_URL`
* You must update nginx configuration: https://github.com/Chocobozzz/PeerTube/blob/develop/support/nginx/peertube
* `location ~ ^/static/(thumbnails|avatars)/ {` block must be removed
* `location = /api/v1/videos/upload-resumable {` must be updated to `location ~ ^/api/v1/videos/(upload-resumable|([^/]+/source/replace-resumable))$ {`
* `location ~ ^(/static/(webseed|streaming-playlists)/private/)|^/download {` must be updated to `location ~ ^(/static/(webseed|web-videos|streaming-playlists)/private/)|^/download {`
* `location ~ ^/static/(webseed|redundancy|streaming-playlists)/ {` must be updated to `location ~ ^/static/(webseed|web-videos|redundancy|streaming-playlists)/ {`
* Tracing requires `--experimental-loader=@opentelemetry/instrumentation/hook.mjs` node option: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L264
#### Developers important notes
* REST API breaking changes:
* Removed `webtorrentEnabled` from user response (deprecated since 4.1 in favour of `p2pEnabled`)
* Removed `avatar` and `banner` fields from account/channel responses (deprecated since 4.2 in favour of `avatars` and `banners`)
* Removed `filter` query when listing videos (deprecated since 4.0 in favour of `isLocal` and `include`)
* Deprecate `/api/v1/videos/:id/webtorrent` video file routes in favour of `/api/v1/videos/:id/web-videos` routes
* Deprecate `hasWebtorrentFiles` body video filter in favour of `hasWebVideoFiles` when listing videos
* Deprecate `webtorrent` `transcodingType` in favour of `web-video` in `/api/v1/videos/{id}/transcoding` route
* `currentTime` is now required to notify the user is watching the video using `/api/v1/videos/{id}/views` (introduced in 4.2)
* Static server paths breaking changes:
* `/static/webseed/...` is deprecated in favour of `/static/web-videos/...`
* `/object-storage-proxy/webseed/...` is deprecated in favour of `/object-storage-proxy/web-videos/...`
* `/static/thumbnails/...` is deprecated in favour of `/static/lazy-thumbnails/...`
* Plugin API breaking changes:
* Deprecated `webtorrent` key in `getFiles()` helper result. Use `webVideo` instead
### CLI tools
* Removed unmaintained `peertube-import-videos` (also aliased as `peertube import-videos` or `peertube import`) script
* PeerTube remote CLI is much more simpler to install using NPM: https://docs.joinpeertube.org/maintain/tools#remote-peertube-cli
* Support moving video files from object storage to filesystem: https://docs.joinpeertube.org/maintain/tools#move-video-files-from-object-storage-to-filesystem
### Features
* :tada: **Add "Password protected" video privacy** [#5836](https://github.com/Chocobozzz/PeerTube/pull/5836) :tada:
* A single password can be set using the web interface at video upload/import/update
* The [REST API](https://docs.joinpeertube.org/api-rest-reference.html#tag/Video-Passwords) can store as many passwords as you want, allowing developers to use this feature to easily give or revoke access to a video *on the fly*
* Developers that use PeerTube embeds can set the video password using [the embed API](https://docs.joinpeertube.org/api/embed-player#setvideopassword-promise-void)
* :tada: **Add video storyboard support** :tada:
* PeerTube automatically generates a storyboard on video upload/import
* Viewers can see the image around the targeted timecode when hovering the progress bar
* Storyboard of videos uploaded/imported before v6 can be generated by the admin using `npm run create-generate-storyboard-job` command: https://docs.joinpeertube.org/maintain/tools#generate-storyboard
* :tada: **Add ability for users to replace their video file** :tada:
* Has to be enabled by the PeerTube instance administrator
* The user can replace the video file in the *Update Video* page
* The *re-upload* date is displayed under the video player
* :tada: **Add video chapters support** :tada:
* Add chapters in the upload/import/update video page or let PeerTube automatically imports them from the video container/youtube-dl
* Markers are displayed in the player progress bar to symbolize a chapter
* Chapter title is displayed when hovering/touching the player progress bar
* Better video player:
* More efficient as we don't rebuild the player every time the played video changes
* The player keeps the current player settings (playback speed, fullscreen...) when the played video changes
* Automatically adjust the player size to match video ratio
* Improve SEO and video link sharing:
* Use short video/channel/account URLs in sitemap and for canonical tags
* Add JSON-LD tag in embed page
* Embed page does not forbid indexation anymore: we use a canonical tag instead that targets the watch page
* Forbid indexation of remote videos, accounts and channels (instead of providing an invalid canonical tag)
* Truncate OpenGraph/Twitter card link description
* Fix client accessibility and keyboard navigation:
* Fix links in bootstrap alerts color
* Better input placeholder contrast
* Fix video miniature link label
* Add ability to disable hotkeys
* Improve table overall accessibility
* Wrap icons that can lead to an action inside buttons
* Fix left menu admin/my-library menu accessibility
* And many more improvements!
* Improve remote runner management:
* Add ability to remove runner jobs
* Add runner job state quick filter
* Merge registration tokens and runners tables in same page
* Add copy button to copy registration token
* Add ability for admins to force transcoding on a specific video even if it's in broken state (stuck in *To Transcode* for example)
* Add an option to sign federated fetches (ActivityPub based software such as Mastodon may require it to access content)
* Download video file directly from S3 using pre signed URLs
* Lazy download remote video thumbnails to reduce storage
* Improve recommended videos when the watched video doesn't have tags set
* Add more rate limits in configuration (`plugins`, `well-known`, `feeds`, `activity_pub` and `client` endpoints)
* Add ability to reset video *Originally published at* attribute
* Add ability for admins to set the default user channel name [#6000](https://github.com/Chocobozzz/PeerTube/pull/6000)
* Server now uses [ESM modules](https://nodejs.org/api/esm.html)
* Add worker threads Prometheus metrics
* Performance:
* Process unicast HTTP job in worker threads
* Sign ActivityPub requests in worker threads
* Optimize recommended videos HTTP request
* Optimize videos SQL queries when filtering on lives or tags
* Optimize `/videos/{id}/views` endpoint with many viewers
* Add ability to disable PeerTube HTTP logs
* Optimize homepage videos HTTP queries
### Bug fixes
* Don't cache upload response if the video has been deleted
* Fix broken upgrade script when using custom database port
* Prevent duplicate runner names
* Avoid runner job update error
* Notify remote runners there are available jobs when a job is aborted/errored
* Fix updating P2P settings in left menu
* Fix 500 HTTP error on invalid short UUID conversion
* Don't display admin email in `security.txt` well-known endpoint
* Optimize `update-host` script to fix out of memory error
* Fix error log when using an unconventional distribution of FFmpeg with a non-standard version string [#5917](https://github.com/Chocobozzz/PeerTube/pull/5917)
* Fix live replay REST API breaking change: `replaySettings.privacy` is not required anymore
* Fix broken live replay when updating replay privacy
* More robust *About* page when getting category from server
* Fix `ERR_HTTP_HEADERS_SENT` crash
* Avoid illegal characters in torrent filename
* Avoid federation error log with remote `Like` on `Note`
* Fix atom feed with *Science & Technology* category
* Support empty value returned by `filter:api.video.get.result` hook
* Prevent remote subscribe on accounts (not yet supported by PeerTube)
* Fix feed audio file mimetype
* Fix video quality on high video resolution/fps
* Fix disabling Object Storage ACL using Docker env `PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC` and `PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PRIVATE` in `.env`
* Correctly end live session on ffprobe error
* Fix video stats X axis with old videos
* Fix empty master playlist upload on s3
* Correctly generate `production.yaml.new` that should merge your current `production.yaml` with new keys defined by PeerTube
* Fix card font color theme
* Respect "transcode original resolution" setting when using remote runners
* Prevent player mobile buttons flickering
* Fix graph zooming end date
## v5.2.1 ## v5.2.1
### Bug fixes ### Bug fixes
@ -16,7 +201,7 @@
* **Important** Remove NodeJS 14 support * **Important** Remove NodeJS 14 support
* **Important** You must update your nginx configuration to support remote runners: https://github.com/Chocobozzz/PeerTube/blob/develop/support/nginx/peertube#L101 * **Important** You must update your nginx configuration to support remote runners: https://github.com/Chocobozzz/PeerTube/blob/develop/support/nginx/peertube#L101
* Add `storage.tmp_persistent` directory in configuration file. **You must configure it in your production.yaml**: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L128 * Add `storage.tmp_persistent` directory in configuration file. **You must configure it in your production.yaml**: https://github.com/Chocobozzz/PeerTube/blob/develop/config/production.yaml.example#L148
* PeerTube requires **Docker Compose >= v2** for Docker compose installation * PeerTube requires **Docker Compose >= v2** for Docker compose installation
### Maintenance ### Maintenance

View File

@ -11,30 +11,30 @@
* Filip Bengtsson * Filip Bengtsson
* Ihor Hordiichuk * Ihor Hordiichuk
* Jeff Huang * Jeff Huang
* Payman Moghadam
* Simon Brosdetzko * Simon Brosdetzko
* kontrollanten * kontrollanten
* Jiri Podhorecky * Jiri Podhorecky
* Payman Moghadam
* Phongpanot * Phongpanot
* hecko * hecko
* Laurent Ettouati
* Milo Ivir * Milo Ivir
* Laurent Ettouati
* kimsible * kimsible
* Zet * Zet
* GunChleoc * GunChleoc
* Clemens Schielicke * Clemens Schielicke
* Racida S * Racida S
* Marcin Mikołajczak
* Ewout van Mansom
* Eivind Ødegård
* Sveinn í Felli * Sveinn í Felli
* Ewout van Mansom
* Marcin Mikołajczak
* Eivind Ødegård
* Tirifto * Tirifto
* Kim * Kim
* Wicklow
* Armin * Armin
* Hannes Ylä-Jääski * Hannes Ylä-Jääski
* Mohamad Reza
* Vodoyo Kamal * Vodoyo Kamal
* Wicklow * Mohamad Reza
* John Livingston * John Livingston
* Kimsible * Kimsible
* Besnik Bleta * Besnik Bleta
@ -71,6 +71,7 @@
* jan Seli * jan Seli
* lutangar * lutangar
* 李奕寯 * 李奕寯
* Blood Axe
* Martin Hoefler * Martin Hoefler
* Porrumentzio * Porrumentzio
* Poslovitch * Poslovitch
@ -94,12 +95,10 @@
* Ms Kimsible * Ms Kimsible
* Thomas Citharel * Thomas Citharel
* Benjamin Bouvier * Benjamin Bouvier
* Blood Axe
* Joe Bill * Joe Bill
* Kemal Oktay Aktoğan * Kemal Oktay Aktoğan
* Lucas Declercq * Lucas Declercq
* Sirxy * Sirxy
* chris@famichiki.tube
* matograine * matograine
* Alexander Ivanov * Alexander Ivanov
* Daniel Santos * Daniel Santos
@ -151,8 +150,8 @@
* Benjamin Seitz * Benjamin Seitz
* Bob Oob * Bob Oob
* Booteille * Booteille
* Chris Sakura 佐倉くりす on Youtube
* DontUseGithub * DontUseGithub
* Farooq Karimi Zadeh
* I_Automne * I_Automne
* Iñigo * Iñigo
* Joan Montané * Joan Montané
@ -196,7 +195,6 @@
* Eder Etxebarria * Eder Etxebarria
* Ehsan Gholami * Ehsan Gholami
* Elga Ahmad Prayoga * Elga Ahmad Prayoga
* Farooq Karimi Zadeh
* Girish Ramakrishnan * Girish Ramakrishnan
* Hakim Oubouali * Hakim Oubouali
* Hans Meiser * Hans Meiser
@ -206,6 +204,7 @@
* Jocelyn Jaubert * Jocelyn Jaubert
* Johan Fleury * Johan Fleury
* Jurij Podgoršek * Jurij Podgoršek
* Kindred La Boneta
* Kiro * Kiro
* Leopere * Leopere
* Linus * Linus
@ -235,6 +234,7 @@
* Ömer Faruk Çakmak * Ömer Faruk Çakmak
* AQR_Rastiq * AQR_Rastiq
* Al-Hassan Abdel-Raouf * Al-Hassan Abdel-Raouf
* Alecks Gates
* Amos Tamam * Amos Tamam
* Andrew Morgan * Andrew Morgan
* Andy Khit * Andy Khit
@ -246,10 +246,12 @@
* Average Dude * Average Dude
* BitTube * BitTube
* Boo Teille * Boo Teille
* Branislav Pavelka
* Dashie * Dashie
* David Luís Pereira Pires * David Luís Pereira Pires
* David Marzal * David Marzal
* EndoGai * EndoGai
* Ettore Atalan
* Fatih Özsoy * Fatih Özsoy
* FediverseTV * FediverseTV
* Florent Fayolle * Florent Fayolle
@ -265,6 +267,7 @@
* HybridGlucose * HybridGlucose
* J C Worm * J C Worm
* Jan Marsalek * Jan Marsalek
* José M
* Joël Galeran * Joël Galeran
* Julien Lemaire * Julien Lemaire
* Lucas Teixeira * Lucas Teixeira
@ -299,6 +302,7 @@
* libertas * libertas
* merty * merty
* plr20 * plr20
* q_h
* qwerty * qwerty
* spf * spf
* taziden * taziden
@ -316,7 +320,6 @@
* Agron * Agron
* Aitozl * Aitozl
* Alberto Mardegan * Alberto Mardegan
* Alecks Gates
* Alejandro Criado-Pérez * Alejandro Criado-Pérez
* Aleksandr Sokolov * Aleksandr Sokolov
* Alexander F. Rødseth * Alexander F. Rødseth
@ -342,7 +345,6 @@
* Cadence Ember * Cadence Ember
* Cale * Cale
* Charles de Lacombe * Charles de Lacombe
* Chris Sakura 佐倉くりす on Youtube - 日本語は第二言語やけ、間違っとったら思いっきり叩いてくださいw つたない日本語ばっかりやけど頑張りまーす♪
* Christoph Geschwind * Christoph Geschwind
* Chronos * Chronos
* Claude * Claude
@ -382,6 +384,7 @@
* Iván Cabaleiro * Iván Cabaleiro
* J Webb * J Webb
* Jacen * Jacen
* Jackson Chen
* Jacob * Jacob
* Jacques Foucry * Jacques Foucry
* Jagannath Bhat * Jagannath Bhat
@ -491,6 +494,7 @@
* Vagelis F * Vagelis F
* Varik Valefor * Varik Valefor
* Vegard Fjeldberg * Vegard Fjeldberg
* Victor Hampel
* Vik * Vik
* Vincent Stakenburg * Vincent Stakenburg
* WhiredPlanck * WhiredPlanck
@ -540,7 +544,6 @@
* philippe lhardy * philippe lhardy
* pitchum * pitchum
* potedeo * potedeo
* q_h
* rdxuan * rdxuan
* retiolus * retiolus
* ruvilonix * ruvilonix

View File

@ -116,7 +116,7 @@ Be it as a user or an instance administrator, you can decide what your experienc
<h3 align="right">Communities that help each other</h3> <h3 align="right">Communities that help each other</h3>
<p align="right"> <p align="right">
In addition to visitors using WebTorrent to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/contribute/architecture#redundancy-between-instances">redundancy guide</a>). In addition to visitors using P2P with WebRTC to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/contribute/architecture#redundancy-between-instances">redundancy guide</a>).
</p> </p>
<p align="right"> <p align="right">
Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and alter creativity (more about that in our <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/FAQ.md">FAQ</a>). Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and alter creativity (more about that in our <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/FAQ.md">FAQ</a>).

View File

@ -0,0 +1,4 @@
src
meta.json
tsconfig.json
scripts

View File

@ -0,0 +1,43 @@
# PeerTube CLI
## Usage
See https://docs.joinpeertube.org/maintain/tools#remote-tools
## Dev
## Install dependencies
```bash
cd peertube-root
yarn install --pure-lockfile
cd apps/peertube-cli && yarn install --pure-lockfile
```
## Develop
```bash
cd peertube-root
npm run dev:peertube-cli
```
## Build
```bash
cd peertube-root
npm run build:peertube-cli
```
## Run
```bash
cd peertube-root
node apps/peertube-cli/dist/peertube-cli.js --help
```
## Publish on NPM
```bash
cd peertube-root
(cd apps/peertube-cli && npm version patch) && npm run build:peertube-cli && (cd apps/peertube-cli && npm publish --access=public)
```

View File

@ -0,0 +1,19 @@
{
"name": "@peertube/peertube-cli",
"version": "1.0.1",
"type": "module",
"main": "dist/peertube.js",
"bin": "dist/peertube.js",
"engines": {
"node": ">=16.x"
},
"scripts": {},
"license": "AGPL-3.0",
"private": false,
"devDependencies": {
"application-config": "^2.0.0",
"cli-table3": "^0.6.0",
"netrc-parser": "^3.1.6"
},
"dependencies": {}
}

View File

@ -0,0 +1,27 @@
import * as esbuild from 'esbuild'
import { readFileSync } from 'fs'
const packageJSON = JSON.parse(readFileSync(new URL('../package.json', import.meta.url)))
export const esbuildOptions = {
entryPoints: [ './src/peertube.ts' ],
bundle: true,
platform: 'node',
format: 'esm',
target: 'node16',
external: [
'./lib-cov/fluent-ffmpeg',
'pg-hstore'
],
outfile: './dist/peertube.js',
banner: {
js: `const require = (await import("node:module")).createRequire(import.meta.url);` +
`const __filename = (await import("node:url")).fileURLToPath(import.meta.url);` +
`const __dirname = (await import("node:path")).dirname(__filename);`
},
define: {
'process.env.PACKAGE_VERSION': `'${packageJSON.version}'`
}
}
await esbuild.build(esbuildOptions)

View File

@ -0,0 +1,7 @@
import * as esbuild from 'esbuild'
import { esbuildOptions } from './build.js'
const context = await esbuild.context(esbuildOptions)
// Enable watch mode
await context.watch()

View File

@ -0,0 +1,171 @@
import CliTable3 from 'cli-table3'
import prompt from 'prompt'
import { Command } from '@commander-js/extra-typings'
import { assignToken, buildServer, getNetrc, getSettings, writeSettings } from './shared/index.js'
export function defineAuthProgram () {
const program = new Command()
.name('auth')
.description('Register your accounts on remote instances to use them with other commands')
program
.command('add')
.description('remember your accounts on remote instances for easier use')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('--default', 'add the entry as the new default')
.action(options => {
/* eslint-disable no-import-assign */
prompt.override = options
prompt.start()
prompt.get({
properties: {
url: {
description: 'instance url',
conform: value => isURLaPeerTubeInstance(value),
message: 'It should be an URL (https://peertube.example.com)',
required: true
},
username: {
conform: value => typeof value === 'string' && value.length !== 0,
message: 'Name must be only letters, spaces, or dashes',
required: true
},
password: {
hidden: true,
replace: '*',
required: true
}
}
}, async (_, result) => {
// Check credentials
try {
// Strip out everything after the domain:port.
// See https://github.com/Chocobozzz/PeerTube/issues/3520
result.url = stripExtraneousFromPeerTubeUrl(result.url)
const server = buildServer(result.url)
await assignToken(server, result.username, result.password)
} catch (err) {
console.error(err.message)
process.exit(-1)
}
await setInstance(result.url, result.username, result.password, options.default)
process.exit(0)
})
})
program
.command('del <url>')
.description('Unregisters a remote instance')
.action(async url => {
await delInstance(url)
process.exit(0)
})
program
.command('list')
.description('List registered remote instances')
.action(async () => {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
const table = new CliTable3({
head: [ 'instance', 'login' ],
colWidths: [ 30, 30 ]
}) as any
settings.remotes.forEach(element => {
if (!netrc.machines[element]) return
table.push([
element,
netrc.machines[element].login
])
})
console.log(table.toString())
process.exit(0)
})
program
.command('set-default <url>')
.description('Set an existing entry as default')
.action(async url => {
const settings = await getSettings()
const instanceExists = settings.remotes.includes(url)
if (instanceExists) {
settings.default = settings.remotes.indexOf(url)
await writeSettings(settings)
process.exit(0)
} else {
console.log('<url> is not a registered instance.')
process.exit(-1)
}
})
program.addHelpText('after', '\n\n Examples:\n\n' +
' $ peertube auth add -u https://peertube.cpy.re -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"\n' +
' $ peertube auth add -u https://peertube.cpy.re -U root\n' +
' $ peertube auth list\n' +
' $ peertube auth del https://peertube.cpy.re\n'
)
return program
}
// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------
async function delInstance (url: string) {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
const index = settings.remotes.indexOf(url)
settings.remotes.splice(index)
if (settings.default === index) settings.default = -1
await writeSettings(settings)
delete netrc.machines[url]
await netrc.save()
}
async function setInstance (url: string, username: string, password: string, isDefault: boolean) {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
if (settings.remotes.includes(url) === false) {
settings.remotes.push(url)
}
if (isDefault || settings.remotes.length === 1) {
settings.default = settings.remotes.length - 1
}
await writeSettings(settings)
netrc.machines[url] = { login: username, password }
await netrc.save()
}
function isURLaPeerTubeInstance (url: string) {
return url.startsWith('http://') || url.startsWith('https://')
}
function stripExtraneousFromPeerTubeUrl (url: string) {
// Get everything before the 3rd /.
const urlLength = url.includes('/', 8)
? url.indexOf('/', 8)
: url.length
return url.substring(0, urlLength)
}

View File

@ -0,0 +1,39 @@
import { Command } from '@commander-js/extra-typings'
import { assignToken, buildServer } from './shared/index.js'
export function defineGetAccessProgram () {
const program = new Command()
.name('get-access-token')
.description('Get a peertube access token')
.alias('token')
program
.option('-u, --url <url>', 'Server url')
.option('-n, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.action(async options => {
try {
if (
!options.url ||
!options.username ||
!options.password
) {
if (!options.url) console.error('--url field is required.')
if (!options.username) console.error('--username field is required.')
if (!options.password) console.error('--password field is required.')
process.exit(-1)
}
const server = buildServer(options.url)
await assignToken(server, options.username, options.password)
console.log(server.accessToken)
} catch (err) {
console.error('Cannot get access token: ' + err.message)
process.exit(-1)
}
})
return program
}

View File

@ -0,0 +1,167 @@
import CliTable3 from 'cli-table3'
import { isAbsolute } from 'path'
import { Command } from '@commander-js/extra-typings'
import { PluginType, PluginType_Type } from '@peertube/peertube-models'
import { assignToken, buildServer, CommonProgramOptions, getServerCredentials } from './shared/index.js'
export function definePluginsProgram () {
const program = new Command()
program
.name('plugins')
.description('Manage instance plugins/themes')
.alias('p')
program
.command('list')
.description('List installed plugins')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('-t, --only-themes', 'List themes only')
.option('-P, --only-plugins', 'List plugins only')
.action(async options => {
try {
await pluginsListCLI(options)
} catch (err) {
console.error('Cannot list plugins: ' + err.message)
process.exit(-1)
}
})
program
.command('install')
.description('Install a plugin or a theme')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('-P --path <path>', 'Install from a path')
.option('-n, --npm-name <npmName>', 'Install from npm')
.option('--plugin-version <pluginVersion>', 'Specify the plugin version to install (only available when installing from npm)')
.action(async options => {
try {
await installPluginCLI(options)
} catch (err) {
console.error('Cannot install plugin: ' + err.message)
process.exit(-1)
}
})
program
.command('update')
.description('Update a plugin or a theme')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('-P --path <path>', 'Update from a path')
.option('-n, --npm-name <npmName>', 'Update from npm')
.action(async options => {
try {
await updatePluginCLI(options)
} catch (err) {
console.error('Cannot update plugin: ' + err.message)
process.exit(-1)
}
})
program
.command('uninstall')
.description('Uninstall a plugin or a theme')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('-n, --npm-name <npmName>', 'NPM plugin/theme name')
.action(async options => {
try {
await uninstallPluginCLI(options)
} catch (err) {
console.error('Cannot uninstall plugin: ' + err.message)
process.exit(-1)
}
})
return program
}
// ----------------------------------------------------------------------------
async function pluginsListCLI (options: CommonProgramOptions & { onlyThemes?: true, onlyPlugins?: true }) {
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
let pluginType: PluginType_Type
if (options.onlyThemes) pluginType = PluginType.THEME
if (options.onlyPlugins) pluginType = PluginType.PLUGIN
const { data } = await server.plugins.list({ start: 0, count: 100, sort: 'name', pluginType })
const table = new CliTable3({
head: [ 'name', 'version', 'homepage' ],
colWidths: [ 50, 20, 50 ]
}) as any
for (const plugin of data) {
const npmName = plugin.type === PluginType.PLUGIN
? 'peertube-plugin-' + plugin.name
: 'peertube-theme-' + plugin.name
table.push([
npmName,
plugin.version,
plugin.homepage
])
}
console.log(table.toString())
}
async function installPluginCLI (options: CommonProgramOptions & { path?: string, npmName?: string, pluginVersion?: string }) {
if (!options.path && !options.npmName) {
throw new Error('You need to specify the npm name or the path of the plugin you want to install.')
}
if (options.path && !isAbsolute(options.path)) {
throw new Error('Path should be absolute.')
}
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
await server.plugins.install({ npmName: options.npmName, path: options.path, pluginVersion: options.pluginVersion })
console.log('Plugin installed.')
}
async function updatePluginCLI (options: CommonProgramOptions & { path?: string, npmName?: string }) {
if (!options.path && !options.npmName) {
throw new Error('You need to specify the npm name or the path of the plugin you want to update.')
}
if (options.path && !isAbsolute(options.path)) {
throw new Error('Path should be absolute.')
}
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
await server.plugins.update({ npmName: options.npmName, path: options.path })
console.log('Plugin updated.')
}
async function uninstallPluginCLI (options: CommonProgramOptions & { npmName?: string }) {
if (!options.npmName) {
throw new Error('You need to specify the npm name of the plugin/theme you want to uninstall.')
}
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
await server.plugins.uninstall({ npmName: options.npmName })
console.log('Plugin uninstalled.')
}

View File

@ -0,0 +1,186 @@
import bytes from 'bytes'
import CliTable3 from 'cli-table3'
import { URL } from 'url'
import { Command } from '@commander-js/extra-typings'
import { forceNumber, uniqify } from '@peertube/peertube-core-utils'
import { HttpStatusCode, VideoRedundanciesTarget } from '@peertube/peertube-models'
import { assignToken, buildServer, CommonProgramOptions, getServerCredentials } from './shared/index.js'
export function defineRedundancyProgram () {
const program = new Command()
.name('redundancy')
.description('Manage instance redundancies')
.alias('r')
program
.command('list-remote-redundancies')
.description('List remote redundancies on your videos')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.action(async options => {
try {
await listRedundanciesCLI({ target: 'my-videos', ...options })
} catch (err) {
console.error('Cannot list remote redundancies: ' + err.message)
process.exit(-1)
}
})
program
.command('list-my-redundancies')
.description('List your redundancies of remote videos')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.action(async options => {
try {
await listRedundanciesCLI({ target: 'remote-videos', ...options })
} catch (err) {
console.error('Cannot list redundancies: ' + err.message)
process.exit(-1)
}
})
program
.command('add')
.description('Duplicate a video in your redundancy system')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.requiredOption('-v, --video <videoId>', 'Video id to duplicate', parseInt)
.action(async options => {
try {
await addRedundancyCLI(options)
} catch (err) {
console.error('Cannot duplicate video: ' + err.message)
process.exit(-1)
}
})
program
.command('remove')
.description('Remove a video from your redundancies')
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.requiredOption('-v, --video <videoId>', 'Video id to remove from redundancies', parseInt)
.action(async options => {
try {
await removeRedundancyCLI(options)
} catch (err) {
console.error('Cannot remove redundancy: ' + err)
process.exit(-1)
}
})
return program
}
// ----------------------------------------------------------------------------
async function listRedundanciesCLI (options: CommonProgramOptions & { target: VideoRedundanciesTarget }) {
const { target } = options
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
const { data } = await server.redundancy.listVideos({ start: 0, count: 100, sort: 'name', target })
const table = new CliTable3({
head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ]
}) as any
for (const redundancy of data) {
const webVideoFiles = redundancy.redundancies.files
const streamingPlaylists = redundancy.redundancies.streamingPlaylists
let totalSize = ''
if (target === 'remote-videos') {
const tmp = webVideoFiles.concat(streamingPlaylists)
.reduce((a, b) => a + b.size, 0)
// FIXME: don't use external dependency to stringify bytes: we already have the functions in the client
totalSize = bytes(tmp)
}
const instances = uniqify(
webVideoFiles.concat(streamingPlaylists)
.map(r => r.fileUrl)
.map(u => new URL(u).host)
)
table.push([
redundancy.id.toString(),
redundancy.name,
redundancy.url,
webVideoFiles.length,
streamingPlaylists.length,
instances.join('\n'),
totalSize
])
}
console.log(table.toString())
}
async function addRedundancyCLI (options: { video: number } & CommonProgramOptions) {
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
if (!options.video || isNaN(options.video)) {
throw new Error('You need to specify the video id to duplicate and it should be a number.')
}
try {
await server.redundancy.addVideo({ videoId: options.video })
console.log('Video will be duplicated by your instance!')
} catch (err) {
if (err.message.includes(HttpStatusCode.CONFLICT_409)) {
throw new Error('This video is already duplicated by your instance.')
}
if (err.message.includes(HttpStatusCode.NOT_FOUND_404)) {
throw new Error('This video id does not exist.')
}
throw err
}
}
async function removeRedundancyCLI (options: CommonProgramOptions & { video: number }) {
const { url, username, password } = await getServerCredentials(options)
const server = buildServer(url)
await assignToken(server, username, password)
if (!options.video || isNaN(options.video)) {
throw new Error('You need to specify the video id to remove from your redundancies')
}
const videoId = forceNumber(options.video)
const myVideoRedundancies = await server.redundancy.listVideos({ target: 'my-videos' })
let videoRedundancy = myVideoRedundancies.data.find(r => videoId === r.id)
if (!videoRedundancy) {
const remoteVideoRedundancies = await server.redundancy.listVideos({ target: 'remote-videos' })
videoRedundancy = remoteVideoRedundancies.data.find(r => videoId === r.id)
}
if (!videoRedundancy) {
throw new Error('Video redundancy not found.')
}
const ids = videoRedundancy.redundancies.files
.concat(videoRedundancy.redundancies.streamingPlaylists)
.map(r => r.id)
for (const id of ids) {
await server.redundancy.removeVideo({ redundancyId: id })
}
console.log('Video redundancy removed!')
}

View File

@ -0,0 +1,167 @@
import { access, constants } from 'fs/promises'
import { isAbsolute } from 'path'
import { inspect } from 'util'
import { Command } from '@commander-js/extra-typings'
import { VideoPrivacy } from '@peertube/peertube-models'
import { PeerTubeServer } from '@peertube/peertube-server-commands'
import { assignToken, buildServer, getServerCredentials, listOptions } from './shared/index.js'
type UploadOptions = {
url?: string
username?: string
password?: string
thumbnail?: string
preview?: string
file?: string
videoName?: string
category?: string
licence?: string
language?: string
tags?: string
nsfw?: true
videoDescription?: string
privacy?: number
channelName?: string
noCommentsEnabled?: true
support?: string
noWaitTranscoding?: true
noDownloadEnabled?: true
}
export function defineUploadProgram () {
const program = new Command('upload')
.description('Upload a video on a PeerTube instance')
.alias('up')
program
.option('-u, --url <url>', 'Server url')
.option('-U, --username <username>', 'Username')
.option('-p, --password <token>', 'Password')
.option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path')
.option('-v, --preview <previewPath>', 'Preview path')
.option('-f, --file <file>', 'Video absolute file path')
.option('-n, --video-name <name>', 'Video name')
.option('-c, --category <category_number>', 'Category number')
.option('-l, --licence <licence_number>', 'Licence number')
.option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)')
.option('-t, --tags <tags>', 'Video tags', listOptions)
.option('-N, --nsfw', 'Video is Not Safe For Work')
.option('-d, --video-description <description>', 'Video description')
.option('-P, --privacy <privacy_number>', 'Privacy', parseInt)
.option('-C, --channel-name <channel_name>', 'Channel name')
.option('--no-comments-enabled', 'Disable video comments')
.option('-s, --support <support>', 'Video support text')
.option('--no-wait-transcoding', 'Do not wait transcoding before publishing the video')
.option('--no-download-enabled', 'Disable video download')
.option('-v, --verbose <verbose>', 'Verbosity, from 0/\'error\' to 4/\'debug\'', 'info')
.action(async options => {
try {
const { url, username, password } = await getServerCredentials(options)
if (!options.videoName || !options.file) {
if (!options.videoName) console.error('--video-name is required.')
if (!options.file) console.error('--file is required.')
process.exit(-1)
}
if (isAbsolute(options.file) === false) {
console.error('File path should be absolute.')
process.exit(-1)
}
await run({ ...options, url, username, password })
} catch (err) {
console.error('Cannot upload video: ' + err.message)
process.exit(-1)
}
})
return program
}
// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------
async function run (options: UploadOptions) {
const { url, username, password } = options
const server = buildServer(url)
await assignToken(server, username, password)
await access(options.file, constants.F_OK)
console.log('Uploading %s video...', options.videoName)
const baseAttributes = await buildVideoAttributesFromCommander(server, options)
const attributes = {
...baseAttributes,
fixture: options.file,
thumbnailfile: options.thumbnail,
previewfile: options.preview
}
try {
await server.videos.upload({ attributes })
console.log(`Video ${options.videoName} uploaded.`)
process.exit(0)
} catch (err) {
const message = err.message || ''
if (message.includes('413')) {
console.error('Aborted: user quota is exceeded or video file is too big for this PeerTube instance.')
} else {
console.error(inspect(err))
}
process.exit(-1)
}
}
async function buildVideoAttributesFromCommander (server: PeerTubeServer, options: UploadOptions, defaultAttributes: any = {}) {
const defaultBooleanAttributes = {
nsfw: false,
commentsEnabled: true,
downloadEnabled: true,
waitTranscoding: true
}
const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {}
for (const key of Object.keys(defaultBooleanAttributes)) {
if (options[key] !== undefined) {
booleanAttributes[key] = options[key]
} else if (defaultAttributes[key] !== undefined) {
booleanAttributes[key] = defaultAttributes[key]
} else {
booleanAttributes[key] = defaultBooleanAttributes[key]
}
}
const videoAttributes = {
name: options.videoName || defaultAttributes.name,
category: options.category || defaultAttributes.category || undefined,
licence: options.licence || defaultAttributes.licence || undefined,
language: options.language || defaultAttributes.language || undefined,
privacy: options.privacy || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
support: options.support || defaultAttributes.support || undefined,
description: options.videoDescription || defaultAttributes.description || undefined,
tags: options.tags || defaultAttributes.tags || undefined
}
Object.assign(videoAttributes, booleanAttributes)
if (options.channelName) {
const videoChannel = await server.channels.get({ channelName: options.channelName })
Object.assign(videoAttributes, { channelId: videoChannel.id })
if (!videoAttributes.support && videoChannel.support) {
Object.assign(videoAttributes, { support: videoChannel.support })
}
}
return videoAttributes
}

View File

@ -1,32 +1,24 @@
#!/usr/bin/env node #!/usr/bin/env node
import { CommandOptions, program } from 'commander' import { Command } from '@commander-js/extra-typings'
import { getSettings, version } from './shared' import { defineAuthProgram } from './peertube-auth.js'
import { defineGetAccessProgram } from './peertube-get-access-token.js'
import { definePluginsProgram } from './peertube-plugins.js'
import { defineRedundancyProgram } from './peertube-redundancy.js'
import { defineUploadProgram } from './peertube-upload.js'
import { getSettings, version } from './shared/index.js'
const program = new Command()
program program
.version(version, '-v, --version') .version(version, '-v, --version')
.usage('[command] [options]') .usage('[command] [options]')
/* Subcommands automatically loaded in the directory and beginning by peertube-* */ program.addCommand(defineAuthProgram())
program program.addCommand(defineUploadProgram())
.command('auth [action]', 'register your accounts on remote instances to use them with other commands') program.addCommand(defineRedundancyProgram())
.command('upload', 'upload a video').alias('up') program.addCommand(definePluginsProgram())
.command('import-videos', 'import a video from a streaming platform').alias('import') program.addCommand(defineGetAccessProgram())
.command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token')
.command('plugins [action]', 'manage instance plugins/themes').alias('p')
.command('redundancy [action]', 'manage instance redundancies').alias('r')
/* Not Yet Implemented */
program
.command(
'diagnostic [action]',
'like couple therapy, but for your instance',
{ noHelp: true } as CommandOptions
).alias('d')
.command('admin',
'manage an instance where you have elevated rights',
{ noHelp: true } as CommandOptions
).alias('a')
// help on no command // help on no command
if (!process.argv.slice(2).length) { if (!process.argv.slice(2).length) {

View File

@ -1,19 +1,23 @@
import { Command } from 'commander' import applicationConfig from 'application-config'
import { Netrc } from 'netrc-parser' import { Netrc } from 'netrc-parser'
import { join } from 'path' import { join } from 'path'
import { createLogger, format, transports } from 'winston' import { createLogger, format, transports } from 'winston'
import { getAppNumber, isTestInstance } from '@server/helpers/core-utils' import { UserRole } from '@peertube/peertube-models'
import { loadLanguages } from '@server/initializers/constants' import { getAppNumber, isTestInstance, root } from '@peertube/peertube-node-utils'
import { root } from '@shared/core-utils' import { PeerTubeServer } from '@peertube/peertube-server-commands'
import { UserRole, VideoPrivacy } from '@shared/models'
import { PeerTubeServer } from '@shared/server-commands' export type CommonProgramOptions = {
url?: string
username?: string
password?: string
}
let configName = 'PeerTube/CLI' let configName = 'PeerTube/CLI'
if (isTestInstance()) configName += `-${getAppNumber()}` if (isTestInstance()) configName += `-${getAppNumber()}`
const config = require('application-config')(configName) const config = applicationConfig(configName)
const version = require(join(root(), 'package.json')).version const version: string = process.env.PACKAGE_VERSION
async function getAdminTokenOrDie (server: PeerTubeServer, username: string, password: string) { async function getAdminTokenOrDie (server: PeerTubeServer, username: string, password: string) {
const token = await server.login.getAccessToken(username, password) const token = await server.login.getAccessToken(username, password)
@ -32,13 +36,13 @@ interface Settings {
default: number default: number
} }
async function getSettings (): Promise<Settings> { async function getSettings () {
const defaultSettings = { const defaultSettings: Settings = {
remotes: [], remotes: [],
default: -1 default: -1
} }
const data = await config.read() const data = await config.read() as Promise<Settings>
return Object.keys(data).length === 0 return Object.keys(data).length === 0
? defaultSettings ? defaultSettings
@ -46,10 +50,8 @@ async function getSettings (): Promise<Settings> {
} }
async function getNetrc () { async function getNetrc () {
const Netrc = require('netrc-parser').Netrc
const netrc = isTestInstance() const netrc = isTestInstance()
? new Netrc(join(root(), 'test' + getAppNumber(), 'netrc')) ? new Netrc(join(root(import.meta.url), 'test' + getAppNumber(), 'netrc'))
: new Netrc() : new Netrc()
await netrc.load() await netrc.load()
@ -66,11 +68,10 @@ function deleteSettings () {
} }
function getRemoteObjectOrDie ( function getRemoteObjectOrDie (
program: Command, options: CommonProgramOptions,
settings: Settings, settings: Settings,
netrc: Netrc netrc: Netrc
): { url: string, username: string, password: string } { ): { url: string, username: string, password: string } {
const options = program.opts()
function exitIfNoOptions (optionNames: string[], errorPrefix: string = '') { function exitIfNoOptions (optionNames: string[], errorPrefix: string = '') {
let exit = false let exit = false
@ -119,85 +120,18 @@ function getRemoteObjectOrDie (
return { url, username, password } return { url, username, password }
} }
function buildCommonVideoOptions (command: Command) { function listOptions (val: any) {
function list (val) { return val.split(',')
return val.split(',')
}
return command
.option('-n, --video-name <name>', 'Video name')
.option('-c, --category <category_number>', 'Category number')
.option('-l, --licence <licence_number>', 'Licence number')
.option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)')
.option('-t, --tags <tags>', 'Video tags', list)
.option('-N, --nsfw', 'Video is Not Safe For Work')
.option('-d, --video-description <description>', 'Video description')
.option('-P, --privacy <privacy_number>', 'Privacy')
.option('-C, --channel-name <channel_name>', 'Channel name')
.option('--no-comments-enabled', 'Disable video comments')
.option('-s, --support <support>', 'Video support text')
.option('--no-wait-transcoding', 'Do not wait transcoding before publishing the video')
.option('--no-download-enabled', 'Disable video download')
.option('-v, --verbose <verbose>', 'Verbosity, from 0/\'error\' to 4/\'debug\'', 'info')
} }
async function buildVideoAttributesFromCommander (server: PeerTubeServer, command: Command, defaultAttributes: any = {}) { function getServerCredentials (options: CommonProgramOptions) {
const options = command.opts()
const defaultBooleanAttributes = {
nsfw: false,
commentsEnabled: true,
downloadEnabled: true,
waitTranscoding: true
}
const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {}
for (const key of Object.keys(defaultBooleanAttributes)) {
if (options[key] !== undefined) {
booleanAttributes[key] = options[key]
} else if (defaultAttributes[key] !== undefined) {
booleanAttributes[key] = defaultAttributes[key]
} else {
booleanAttributes[key] = defaultBooleanAttributes[key]
}
}
const videoAttributes = {
name: options.videoName || defaultAttributes.name,
category: options.category || defaultAttributes.category || undefined,
licence: options.licence || defaultAttributes.licence || undefined,
language: options.language || defaultAttributes.language || undefined,
privacy: options.privacy || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
support: options.support || defaultAttributes.support || undefined,
description: options.videoDescription || defaultAttributes.description || undefined,
tags: options.tags || defaultAttributes.tags || undefined
}
Object.assign(videoAttributes, booleanAttributes)
if (options.channelName) {
const videoChannel = await server.channels.get({ channelName: options.channelName })
Object.assign(videoAttributes, { channelId: videoChannel.id })
if (!videoAttributes.support && videoChannel.support) {
Object.assign(videoAttributes, { support: videoChannel.support })
}
}
return videoAttributes
}
function getServerCredentials (program: Command) {
return Promise.all([ getSettings(), getNetrc() ]) return Promise.all([ getSettings(), getNetrc() ])
.then(([ settings, netrc ]) => { .then(([ settings, netrc ]) => {
return getRemoteObjectOrDie(program, settings, netrc) return getRemoteObjectOrDie(options, settings, netrc)
}) })
} }
function buildServer (url: string) { function buildServer (url: string) {
loadLanguages()
return new PeerTubeServer({ url }) return new PeerTubeServer({ url })
} }
@ -253,8 +187,7 @@ export {
getServerCredentials, getServerCredentials,
buildCommonVideoOptions, listOptions,
buildVideoAttributesFromCommander,
getAdminTokenOrDie, getAdminTokenOrDie,
buildServer, buildServer,

View File

@ -0,0 +1 @@
export * from './cli.js'

View File

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist",
"rootDir": "src",
"tsBuildInfoFile": "./dist/.tsbuildinfo"
},
"references": [
{ "path": "../../packages/core-utils" },
{ "path": "../../packages/models" },
{ "path": "../../packages/node-utils" },
{ "path": "../../packages/server-commands" }
]
}

View File

@ -3,26 +3,32 @@
"@babel/code-frame@^7.0.0": "@babel/code-frame@^7.0.0":
version "7.16.7" version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==
dependencies: dependencies:
"@babel/highlight" "^7.16.7" "@babel/highlight" "^7.22.10"
chalk "^2.4.2"
"@babel/helper-validator-identifier@^7.16.7": "@babel/helper-validator-identifier@^7.22.5":
version "7.16.7" version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
"@babel/highlight@^7.16.7": "@babel/highlight@^7.22.10":
version "7.16.10" version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7"
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==
dependencies: dependencies:
"@babel/helper-validator-identifier" "^7.16.7" "@babel/helper-validator-identifier" "^7.22.5"
chalk "^2.0.0" chalk "^2.4.2"
js-tokens "^4.0.0" js-tokens "^4.0.0"
"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
@ -36,9 +42,9 @@ ansi-styles@^3.2.1:
color-convert "^1.9.0" color-convert "^1.9.0"
application-config-path@^0.1.0: application-config-path@^0.1.0:
version "0.1.0" version "0.1.1"
resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f" resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.1.tgz#8b5ac64ff6afdd9bd70ce69f6f64b6998f5f756e"
integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8= integrity sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==
application-config@^2.0.0: application-config@^2.0.0:
version "2.0.0" version "2.0.0"
@ -49,7 +55,7 @@ application-config@^2.0.0:
load-json-file "^6.2.0" load-json-file "^6.2.0"
write-json-file "^4.2.0" write-json-file "^4.2.0"
chalk@^2.0.0: chalk@^2.4.2:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@ -59,13 +65,13 @@ chalk@^2.0.0:
supports-color "^5.3.0" supports-color "^5.3.0"
cli-table3@^0.6.0: cli-table3@^0.6.0:
version "0.6.1" version "0.6.3"
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.1.tgz#36ce9b7af4847f288d3cdd081fbd09bf7bd237b8" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2"
integrity sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA== integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==
dependencies: dependencies:
string-width "^4.2.0" string-width "^4.2.0"
optionalDependencies: optionalDependencies:
colors "1.4.0" "@colors/colors" "1.5.0"
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
@ -77,12 +83,7 @@ color-convert@^1.9.0:
color-name@1.1.3: color-name@1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
colors@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
cross-spawn@^6.0.0: cross-spawn@^6.0.0:
version "6.0.5" version "6.0.5"
@ -122,7 +123,7 @@ error-ex@^1.3.1:
escape-string-regexp@^1.0.5: escape-string-regexp@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
execa@^0.10.0: execa@^0.10.0:
version "0.10.0" version "0.10.0"
@ -140,27 +141,27 @@ execa@^0.10.0:
get-stream@^3.0.0: get-stream@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==
graceful-fs@^4.1.15: graceful-fs@^4.1.15:
version "4.2.9" version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
has-flag@^3.0.0: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
imurmurhash@^0.1.4: imurmurhash@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
is-arrayish@^0.2.1: is-arrayish@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-fullwidth-code-point@^3.0.0: is-fullwidth-code-point@^3.0.0:
version "3.0.0" version "3.0.0"
@ -175,17 +176,17 @@ is-plain-obj@^2.0.0:
is-stream@^1.1.0: is-stream@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
is-typedarray@^1.0.0: is-typedarray@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
isexe@^2.0.0: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
js-tokens@^4.0.0: js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
@ -240,14 +241,14 @@ nice-try@^1.0.4:
npm-run-path@^2.0.0: npm-run-path@^2.0.0:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
dependencies: dependencies:
path-key "^2.0.0" path-key "^2.0.0"
p-finally@^1.0.0: p-finally@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
parse-json@^5.0.0: parse-json@^5.0.0:
version "5.2.0" version "5.2.0"
@ -262,29 +263,29 @@ parse-json@^5.0.0:
path-key@^2.0.0, path-key@^2.0.1: path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
semver@^5.5.0: semver@^5.5.0:
version "5.7.1" version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0: semver@^6.0.0:
version "6.3.0" version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
shebang-command@^1.2.0: shebang-command@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
dependencies: dependencies:
shebang-regex "^1.0.0" shebang-regex "^1.0.0"
shebang-regex@^1.0.0: shebang-regex@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
signal-exit@^3.0.0, signal-exit@^3.0.2: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.7" version "3.0.7"
@ -322,7 +323,7 @@ strip-bom@^4.0.0:
strip-eof@^1.0.0: strip-eof@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"

View File

@ -0,0 +1,4 @@
src
meta.json
tsconfig.json
scripts

View File

@ -0,0 +1,43 @@
# PeerTube runner
Runner program to execute jobs (transcoding...) of remote PeerTube instances.
Commands below has to be run at the root of PeerTube git repository.
## Dev
### Install dependencies
```bash
cd peertube-root
yarn install --pure-lockfile
cd apps/peertube-runner && yarn install --pure-lockfile
```
### Develop
```bash
cd peertube-root
npm run dev:peertube-runner
```
### Build
```bash
cd peertube-root
npm run build:peertube-runner
```
### Run
```bash
cd peertube-root
node apps/peertube-runner/dist/peertube-runner.js --help
```
### Publish on NPM
```bash
cd peertube-root
(cd apps/peertube-runner && npm version patch) && npm run build:peertube-runner && (cd apps/peertube-runner && npm publish --access=public)
```

View File

@ -1,15 +1,18 @@
{ {
"name": "@peertube/peertube-runner", "name": "@peertube/peertube-runner",
"version": "0.0.4", "version": "0.0.7",
"type": "module",
"main": "dist/peertube-runner.js", "main": "dist/peertube-runner.js",
"bin": "dist/peertube-runner.js", "bin": "dist/peertube-runner.js",
"engines": {
"node": ">=16.x"
},
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"@commander-js/extra-typings": "^10.0.3", "@commander-js/extra-typings": "^10.0.3",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"env-paths": "^3.0.0", "env-paths": "^3.0.0",
"esbuild": "^0.17.15",
"net-ipc": "^2.0.1", "net-ipc": "^2.0.1",
"pino": "^8.11.0", "pino": "^8.11.0",
"pino-pretty": "^10.0.0" "pino-pretty": "^10.0.0"

View File

@ -0,0 +1,27 @@
import * as esbuild from 'esbuild'
import { readFileSync } from 'fs'
const packageJSON = JSON.parse(readFileSync(new URL('../package.json', import.meta.url)))
export const esbuildOptions = {
entryPoints: [ './src/peertube-runner.ts' ],
bundle: true,
platform: 'node',
format: 'esm',
target: 'node16',
external: [
'./lib-cov/fluent-ffmpeg',
'pg-hstore'
],
outfile: './dist/peertube-runner.js',
banner: {
js: `const require = (await import("node:module")).createRequire(import.meta.url);` +
`const __filename = (await import("node:url")).fileURLToPath(import.meta.url);` +
`const __dirname = (await import("node:path")).dirname(__filename);`
},
define: {
'process.env.PACKAGE_VERSION': `'${packageJSON.version}'`
}
}
await esbuild.build(esbuildOptions)

View File

@ -1,14 +1,12 @@
#!/usr/bin/env node #!/usr/bin/env node
import { Command, InvalidArgumentError } from '@commander-js/extra-typings' import { Command, InvalidArgumentError } from '@commander-js/extra-typings'
import { listRegistered, registerRunner, unregisterRunner } from './register' import { listRegistered, registerRunner, unregisterRunner } from './register/index.js'
import { RunnerServer } from './server' import { RunnerServer } from './server/index.js'
import { ConfigManager, logger } from './shared' import { ConfigManager, logger } from './shared/index.js'
const packageJSON = require('./package.json')
const program = new Command() const program = new Command()
.version(packageJSON.version) .version(process.env.PACKAGE_VERSION)
.option( .option(
'--id <id>', '--id <id>',
'Runner server id, so you can run multiple PeerTube server runners with different configurations on the same machine', 'Runner server id, so you can run multiple PeerTube server runners with different configurations on the same machine',

View File

@ -0,0 +1 @@
export * from './register.js'

View File

@ -1,4 +1,4 @@
import { IPCClient } from '../shared/ipc' import { IPCClient } from '../shared/ipc/index.js'
export async function registerRunner (options: { export async function registerRunner (options: {
url: string url: string

View File

@ -0,0 +1 @@
export * from './server.js'

View File

@ -0,0 +1,2 @@
export * from './shared/index.js'
export * from './process.js'

View File

@ -1,14 +1,14 @@
import { logger } from 'packages/peertube-runner/shared/logger'
import { import {
RunnerJobLiveRTMPHLSTranscodingPayload, RunnerJobLiveRTMPHLSTranscodingPayload,
RunnerJobStudioTranscodingPayload, RunnerJobStudioTranscodingPayload,
RunnerJobVODAudioMergeTranscodingPayload, RunnerJobVODAudioMergeTranscodingPayload,
RunnerJobVODHLSTranscodingPayload, RunnerJobVODHLSTranscodingPayload,
RunnerJobVODWebVideoTranscodingPayload RunnerJobVODWebVideoTranscodingPayload
} from '@shared/models' } from '@peertube/peertube-models'
import { processAudioMergeTranscoding, processHLSTranscoding, ProcessOptions, processWebVideoTranscoding } from './shared' import { logger } from '../../shared/index.js'
import { ProcessLiveRTMPHLSTranscoding } from './shared/process-live' import { processAudioMergeTranscoding, processHLSTranscoding, ProcessOptions, processWebVideoTranscoding } from './shared/index.js'
import { processStudioTranscoding } from './shared/process-studio' import { ProcessLiveRTMPHLSTranscoding } from './shared/process-live.js'
import { processStudioTranscoding } from './shared/process-studio.js'
export async function processJob (options: ProcessOptions) { export async function processJob (options: ProcessOptions) {
const { server, job } = options const { server, job } = options

View File

@ -1,11 +1,11 @@
import { remove } from 'fs-extra' import { remove } from 'fs-extra/esm'
import { ConfigManager, downloadFile, logger } from 'packages/peertube-runner/shared'
import { join } from 'path' import { join } from 'path'
import { buildUUID } from '@shared/extra-utils' import { FFmpegEdition, FFmpegLive, FFmpegVOD, getDefaultAvailableEncoders, getDefaultEncodersToTry } from '@peertube/peertube-ffmpeg'
import { FFmpegEdition, FFmpegLive, FFmpegVOD, getDefaultAvailableEncoders, getDefaultEncodersToTry } from '@shared/ffmpeg' import { RunnerJob, RunnerJobPayload } from '@peertube/peertube-models'
import { RunnerJob, RunnerJobPayload } from '@shared/models' import { buildUUID } from '@peertube/peertube-node-utils'
import { PeerTubeServer } from '@shared/server-commands' import { PeerTubeServer } from '@peertube/peertube-server-commands'
import { getTranscodingLogger } from './transcoding-logger' import { ConfigManager, downloadFile, logger } from '../../../shared/index.js'
import { getTranscodingLogger } from './transcoding-logger.js'
export type JobWithToken <T extends RunnerJobPayload = RunnerJobPayload> = RunnerJob<T> & { jobToken: string } export type JobWithToken <T extends RunnerJobPayload = RunnerJobPayload> = RunnerJob<T> & { jobToken: string }
@ -35,49 +35,48 @@ export async function downloadInputFile (options: {
return destination return destination
} }
export async function updateTranscodingProgress (options: { export function scheduleTranscodingProgress (options: {
server: PeerTubeServer server: PeerTubeServer
runnerToken: string runnerToken: string
job: JobWithToken job: JobWithToken
progress: number progressGetter: () => number
}) { }) {
const { server, job, runnerToken, progress } = options const { job, server, progressGetter, runnerToken } = options
return server.runnerJobs.update({ jobToken: job.jobToken, jobUUID: job.uuid, runnerToken, progress })
}
// ---------------------------------------------------------------------------
export function buildFFmpegVOD (options: {
server: PeerTubeServer
runnerToken: string
job: JobWithToken
}) {
const { server, job, runnerToken } = options
const updateInterval = ConfigManager.Instance.isTestInstance() const updateInterval = ConfigManager.Instance.isTestInstance()
? 500 ? 500
: 60000 : 60000
let progress: number const update = () => {
server.runnerJobs.update({ jobToken: job.jobToken, jobUUID: job.uuid, runnerToken, progress: progressGetter() })
.catch(err => logger.error({ err }, 'Cannot send job progress'))
}
const interval = setInterval(() => { const interval = setInterval(() => {
updateTranscodingProgress({ server, job, runnerToken, progress }) update()
.catch(err => logger.error({ err }, 'Cannot send job progress'))
}, updateInterval) }, updateInterval)
update()
return interval
}
// ---------------------------------------------------------------------------
export function buildFFmpegVOD (options: {
onJobProgress: (progress: number) => void
}) {
const { onJobProgress } = options
return new FFmpegVOD({ return new FFmpegVOD({
...getCommonFFmpegOptions(), ...getCommonFFmpegOptions(),
onError: () => clearInterval(interval),
onEnd: () => clearInterval(interval),
updateJobProgress: arg => { updateJobProgress: arg => {
if (arg < 0 || arg > 100) { const progress = arg < 0 || arg > 100
progress = undefined ? undefined
} else { : arg
progress = arg
} onJobProgress(progress)
} }
}) })
} }

View File

@ -0,0 +1,3 @@
export * from './common.js'
export * from './process-vod.js'
export * from './transcoding-logger.js'

View File

@ -1,20 +1,20 @@
import { FSWatcher, watch } from 'chokidar' import { FSWatcher, watch } from 'chokidar'
import { FfmpegCommand } from 'fluent-ffmpeg' import { FfmpegCommand } from 'fluent-ffmpeg'
import { ensureDir, remove } from 'fs-extra' import { ensureDir, remove } from 'fs-extra/esm'
import { logger } from 'packages/peertube-runner/shared'
import { basename, join } from 'path' import { basename, join } from 'path'
import { wait } from '@shared/core-utils' import { wait } from '@peertube/peertube-core-utils'
import { buildUUID } from '@shared/extra-utils' import { ffprobePromise, getVideoStreamBitrate, getVideoStreamDimensionsInfo, hasAudioStream } from '@peertube/peertube-ffmpeg'
import { ffprobePromise, getVideoStreamBitrate, getVideoStreamDimensionsInfo, hasAudioStream } from '@shared/ffmpeg'
import { import {
LiveRTMPHLSTranscodingSuccess, LiveRTMPHLSTranscodingSuccess,
LiveRTMPHLSTranscodingUpdatePayload, LiveRTMPHLSTranscodingUpdatePayload,
PeerTubeProblemDocument, PeerTubeProblemDocument,
RunnerJobLiveRTMPHLSTranscodingPayload, RunnerJobLiveRTMPHLSTranscodingPayload,
ServerErrorCode ServerErrorCode
} from '@shared/models' } from '@peertube/peertube-models'
import { ConfigManager } from '../../../shared/config-manager' import { buildUUID } from '@peertube/peertube-node-utils'
import { buildFFmpegLive, ProcessOptions } from './common' import { ConfigManager } from '../../../shared/config-manager.js'
import { logger } from '../../../shared/index.js'
import { buildFFmpegLive, ProcessOptions } from './common.js'
export class ProcessLiveRTMPHLSTranscoding { export class ProcessLiveRTMPHLSTranscoding {

View File

@ -1,30 +1,46 @@
import { remove } from 'fs-extra' import { remove } from 'fs-extra/esm'
import { pick } from 'lodash'
import { logger } from 'packages/peertube-runner/shared'
import { join } from 'path' import { join } from 'path'
import { buildUUID } from '@shared/extra-utils' import { pick } from '@peertube/peertube-core-utils'
import { import {
RunnerJobStudioTranscodingPayload, RunnerJobStudioTranscodingPayload,
VideoStudioTranscodingSuccess,
VideoStudioTask, VideoStudioTask,
VideoStudioTaskCutPayload, VideoStudioTaskCutPayload,
VideoStudioTaskIntroPayload, VideoStudioTaskIntroPayload,
VideoStudioTaskOutroPayload, VideoStudioTaskOutroPayload,
VideoStudioTaskPayload, VideoStudioTaskPayload,
VideoStudioTaskWatermarkPayload VideoStudioTaskWatermarkPayload,
} from '@shared/models' VideoStudioTranscodingSuccess
import { ConfigManager } from '../../../shared/config-manager' } from '@peertube/peertube-models'
import { buildFFmpegEdition, downloadInputFile, JobWithToken, ProcessOptions } from './common' import { buildUUID } from '@peertube/peertube-node-utils'
import { ConfigManager } from '../../../shared/config-manager.js'
import { logger } from '../../../shared/index.js'
import { buildFFmpegEdition, downloadInputFile, JobWithToken, ProcessOptions, scheduleTranscodingProgress } from './common.js'
export async function processStudioTranscoding (options: ProcessOptions<RunnerJobStudioTranscodingPayload>) { export async function processStudioTranscoding (options: ProcessOptions<RunnerJobStudioTranscodingPayload>) {
const { server, job, runnerToken } = options const { server, job, runnerToken } = options
const payload = job.payload const payload = job.payload
let inputPath: string
let outputPath: string let outputPath: string
const inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job }) let tmpInputFilePath: string
let tmpInputFilePath = inputPath
let tasksProgress = 0
const updateProgressInterval = scheduleTranscodingProgress({
job,
server,
runnerToken,
progressGetter: () => tasksProgress
})
try { try {
logger.info(`Downloading input file ${payload.input.videoFileUrl} for job ${job.jobToken}`)
inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job })
tmpInputFilePath = inputPath
logger.info(`Input file ${payload.input.videoFileUrl} downloaded for job ${job.jobToken}. Running studio transcoding tasks.`)
for (const task of payload.tasks) { for (const task of payload.tasks) {
const outputFilename = 'output-edition-' + buildUUID() + '.mp4' const outputFilename = 'output-edition-' + buildUUID() + '.mp4'
outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), outputFilename) outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), outputFilename)
@ -41,6 +57,8 @@ export async function processStudioTranscoding (options: ProcessOptions<RunnerJo
// For the next iteration // For the next iteration
tmpInputFilePath = outputPath tmpInputFilePath = outputPath
tasksProgress += Math.floor(100 / payload.tasks.length)
} }
const successBody: VideoStudioTranscodingSuccess = { const successBody: VideoStudioTranscodingSuccess = {
@ -54,8 +72,9 @@ export async function processStudioTranscoding (options: ProcessOptions<RunnerJo
payload: successBody payload: successBody
}) })
} finally { } finally {
await remove(tmpInputFilePath) if (tmpInputFilePath) await remove(tmpInputFilePath)
await remove(outputPath) if (outputPath) await remove(outputPath)
if (updateProgressInterval) clearInterval(updateProgressInterval)
} }
} }

View File

@ -0,0 +1,201 @@
import { remove } from 'fs-extra/esm'
import { join } from 'path'
import {
RunnerJobVODAudioMergeTranscodingPayload,
RunnerJobVODHLSTranscodingPayload,
RunnerJobVODWebVideoTranscodingPayload,
VODAudioMergeTranscodingSuccess,
VODHLSTranscodingSuccess,
VODWebVideoTranscodingSuccess
} from '@peertube/peertube-models'
import { buildUUID } from '@peertube/peertube-node-utils'
import { ConfigManager } from '../../../shared/config-manager.js'
import { logger } from '../../../shared/index.js'
import { buildFFmpegVOD, downloadInputFile, ProcessOptions, scheduleTranscodingProgress } from './common.js'
export async function processWebVideoTranscoding (options: ProcessOptions<RunnerJobVODWebVideoTranscodingPayload>) {
const { server, job, runnerToken } = options
const payload = job.payload
let ffmpegProgress: number
let inputPath: string
const outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), `output-${buildUUID()}.mp4`)
const updateProgressInterval = scheduleTranscodingProgress({
job,
server,
runnerToken,
progressGetter: () => ffmpegProgress
})
try {
logger.info(`Downloading input file ${payload.input.videoFileUrl} for web video transcoding job ${job.jobToken}`)
inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job })
logger.info(`Downloaded input file ${payload.input.videoFileUrl} for job ${job.jobToken}. Running web video transcoding.`)
const ffmpegVod = buildFFmpegVOD({
onJobProgress: progress => { ffmpegProgress = progress }
})
await ffmpegVod.transcode({
type: 'video',
inputPath,
outputPath,
inputFileMutexReleaser: () => {},
resolution: payload.output.resolution,
fps: payload.output.fps
})
const successBody: VODWebVideoTranscodingSuccess = {
videoFile: outputPath
}
await server.runnerJobs.success({
jobToken: job.jobToken,
jobUUID: job.uuid,
runnerToken,
payload: successBody
})
} finally {
if (inputPath) await remove(inputPath)
if (outputPath) await remove(outputPath)
if (updateProgressInterval) clearInterval(updateProgressInterval)
}
}
export async function processHLSTranscoding (options: ProcessOptions<RunnerJobVODHLSTranscodingPayload>) {
const { server, job, runnerToken } = options
const payload = job.payload
let ffmpegProgress: number
let inputPath: string
const uuid = buildUUID()
const outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), `${uuid}-${payload.output.resolution}.m3u8`)
const videoFilename = `${uuid}-${payload.output.resolution}-fragmented.mp4`
const videoPath = join(join(ConfigManager.Instance.getTranscodingDirectory(), videoFilename))
const updateProgressInterval = scheduleTranscodingProgress({
job,
server,
runnerToken,
progressGetter: () => ffmpegProgress
})
try {
logger.info(`Downloading input file ${payload.input.videoFileUrl} for HLS transcoding job ${job.jobToken}`)
inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job })
logger.info(`Downloaded input file ${payload.input.videoFileUrl} for job ${job.jobToken}. Running HLS transcoding.`)
const ffmpegVod = buildFFmpegVOD({
onJobProgress: progress => { ffmpegProgress = progress }
})
await ffmpegVod.transcode({
type: 'hls',
copyCodecs: false,
inputPath,
hlsPlaylist: { videoFilename },
outputPath,
inputFileMutexReleaser: () => {},
resolution: payload.output.resolution,
fps: payload.output.fps
})
const successBody: VODHLSTranscodingSuccess = {
resolutionPlaylistFile: outputPath,
videoFile: videoPath
}
await server.runnerJobs.success({
jobToken: job.jobToken,
jobUUID: job.uuid,
runnerToken,
payload: successBody
})
} finally {
if (inputPath) await remove(inputPath)
if (outputPath) await remove(outputPath)
if (videoPath) await remove(videoPath)
if (updateProgressInterval) clearInterval(updateProgressInterval)
}
}
export async function processAudioMergeTranscoding (options: ProcessOptions<RunnerJobVODAudioMergeTranscodingPayload>) {
const { server, job, runnerToken } = options
const payload = job.payload
let ffmpegProgress: number
let audioPath: string
let inputPath: string
const outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), `output-${buildUUID()}.mp4`)
const updateProgressInterval = scheduleTranscodingProgress({
job,
server,
runnerToken,
progressGetter: () => ffmpegProgress
})
try {
logger.info(
`Downloading input files ${payload.input.audioFileUrl} and ${payload.input.previewFileUrl} ` +
`for audio merge transcoding job ${job.jobToken}`
)
audioPath = await downloadInputFile({ url: payload.input.audioFileUrl, runnerToken, job })
inputPath = await downloadInputFile({ url: payload.input.previewFileUrl, runnerToken, job })
logger.info(
`Downloaded input files ${payload.input.audioFileUrl} and ${payload.input.previewFileUrl} ` +
`for job ${job.jobToken}. Running audio merge transcoding.`
)
const ffmpegVod = buildFFmpegVOD({
onJobProgress: progress => { ffmpegProgress = progress }
})
await ffmpegVod.transcode({
type: 'merge-audio',
audioPath,
inputPath,
outputPath,
inputFileMutexReleaser: () => {},
resolution: payload.output.resolution,
fps: payload.output.fps
})
const successBody: VODAudioMergeTranscodingSuccess = {
videoFile: outputPath
}
await server.runnerJobs.success({
jobToken: job.jobToken,
jobUUID: job.uuid,
runnerToken,
payload: successBody
})
} finally {
if (audioPath) await remove(audioPath)
if (inputPath) await remove(inputPath)
if (outputPath) await remove(outputPath)
if (updateProgressInterval) clearInterval(updateProgressInterval)
}
}

View File

@ -1,4 +1,4 @@
import { logger } from 'packages/peertube-runner/shared/logger' import { logger } from '../../../shared/index.js'
export function getTranscodingLogger () { export function getTranscodingLogger () {
return { return {

View File

@ -1,14 +1,15 @@
import { ensureDir, readdir, remove } from 'fs-extra' import { ensureDir, remove } from 'fs-extra/esm'
import { readdir } from 'fs/promises'
import { join } from 'path' import { join } from 'path'
import { io, Socket } from 'socket.io-client' import { io, Socket } from 'socket.io-client'
import { pick, wait } from '@shared/core-utils' import { pick, shuffle, wait } from '@peertube/peertube-core-utils'
import { PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' import { PeerTubeProblemDocument, ServerErrorCode } from '@peertube/peertube-models'
import { PeerTubeServer as PeerTubeServerCommand } from '@shared/server-commands' import { PeerTubeServer as PeerTubeServerCommand } from '@peertube/peertube-server-commands'
import { ConfigManager } from '../shared' import { ConfigManager } from '../shared/index.js'
import { IPCServer } from '../shared/ipc' import { IPCServer } from '../shared/ipc/index.js'
import { logger } from '../shared/logger' import { logger } from '../shared/logger.js'
import { JobWithToken, processJob } from './process' import { JobWithToken, processJob } from './process/index.js'
import { isJobSupported } from './shared' import { isJobSupported } from './shared/index.js'
type PeerTubeServer = PeerTubeServerCommand & { type PeerTubeServer = PeerTubeServerCommand & {
runnerToken: string runnerToken: string
@ -53,7 +54,7 @@ export class RunnerServer {
} }
// Cleanup on exit // Cleanup on exit
for (const code of [ 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException' ]) { for (const code of [ 'SIGTERM', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException' ]) {
process.on(code, async (err, origin) => { process.on(code, async (err, origin) => {
if (code === 'uncaughtException') { if (code === 'uncaughtException') {
logger.error({ err, origin }, 'uncaughtException') logger.error({ err, origin }, 'uncaughtException')
@ -175,7 +176,7 @@ export class RunnerServer {
let hadAvailableJob = false let hadAvailableJob = false
for (const server of this.servers) { for (const server of shuffle([ ...this.servers ])) {
try { try {
logger.info('Checking available jobs on ' + server.url) logger.info('Checking available jobs on ' + server.url)

View File

@ -0,0 +1 @@
export * from './supported-job.js'

View File

@ -7,7 +7,7 @@ import {
RunnerJobVODHLSTranscodingPayload, RunnerJobVODHLSTranscodingPayload,
RunnerJobVODWebVideoTranscodingPayload, RunnerJobVODWebVideoTranscodingPayload,
VideoStudioTaskPayload VideoStudioTaskPayload
} from '@shared/models' } from '@peertube/peertube-models'
const supportedMatrix = { const supportedMatrix = {
'vod-web-video-transcoding': (_payload: RunnerJobVODWebVideoTranscodingPayload) => { 'vod-web-video-transcoding': (_payload: RunnerJobVODWebVideoTranscodingPayload) => {

View File

@ -1,9 +1,10 @@
import envPaths from 'env-paths'
import { ensureDir, pathExists, readFile, remove, writeFile } from 'fs-extra'
import { merge } from 'lodash'
import { logger } from 'packages/peertube-runner/shared/logger'
import { dirname, join } from 'path'
import { parse, stringify } from '@iarna/toml' import { parse, stringify } from '@iarna/toml'
import envPaths from 'env-paths'
import { ensureDir, pathExists, remove } from 'fs-extra/esm'
import { readFile, writeFile } from 'fs/promises'
import merge from 'lodash-es/merge.js'
import { dirname, join } from 'path'
import { logger } from '../shared/index.js'
const paths = envPaths('peertube-runner') const paths = envPaths('peertube-runner')

View File

@ -1,7 +1,8 @@
import { createWriteStream, remove } from 'fs-extra' import { createWriteStream } from 'fs'
import { remove } from 'fs-extra/esm'
import { request as requestHTTP } from 'http' import { request as requestHTTP } from 'http'
import { request as requestHTTPS, RequestOptions } from 'https' import { request as requestHTTPS, RequestOptions } from 'https'
import { logger } from './logger' import { logger } from './logger.js'
export function downloadFile (options: { export function downloadFile (options: {
url: string url: string

View File

@ -0,0 +1,3 @@
export * from './config-manager.js'
export * from './http.js'
export * from './logger.js'

View File

@ -0,0 +1,2 @@
export * from './ipc-client.js'
export * from './ipc-server.js'

View File

@ -1,8 +1,8 @@
import CliTable3 from 'cli-table3' import CliTable3 from 'cli-table3'
import { ensureDir } from 'fs-extra' import { ensureDir } from 'fs-extra/esm'
import { Client as NetIPC } from 'net-ipc' import { Client as NetIPC } from 'net-ipc'
import { ConfigManager } from '../config-manager' import { ConfigManager } from '../config-manager.js'
import { IPCReponse, IPCReponseData, IPCRequest } from './shared' import { IPCReponse, IPCReponseData, IPCRequest } from './shared/index.js'
export class IPCClient { export class IPCClient {
private netIPC: NetIPC private netIPC: NetIPC

View File

@ -1,10 +1,10 @@
import { ensureDir } from 'fs-extra' import { ensureDir } from 'fs-extra/esm'
import { Server as NetIPC } from 'net-ipc' import { Server as NetIPC } from 'net-ipc'
import { pick } from '@shared/core-utils' import { pick } from '@peertube/peertube-core-utils'
import { RunnerServer } from '../../server' import { RunnerServer } from '../../server/index.js'
import { ConfigManager } from '../config-manager' import { ConfigManager } from '../config-manager.js'
import { logger } from '../logger' import { logger } from '../logger.js'
import { IPCReponse, IPCReponseData, IPCRequest } from './shared' import { IPCReponse, IPCReponseData, IPCRequest } from './shared/index.js'
export class IPCServer { export class IPCServer {
private netIPC: NetIPC private netIPC: NetIPC

View File

@ -0,0 +1,2 @@
export * from './ipc-request.model.js'
export * from './ipc-response.model.js'

View File

@ -1,7 +1,7 @@
import { pino } from 'pino' import { pino } from 'pino'
import pretty from 'pino-pretty' import pretty from 'pino-pretty'
const logger = pino(pretty({ const logger = pino(pretty.default({
colorize: true colorize: true
})) }))

View File

@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist",
"rootDir": "src",
"tsBuildInfoFile": "./dist/.tsbuildinfo"
},
"references": [
{ "path": "../../packages/core-utils" },
{ "path": "../../packages/ffmpeg" },
{ "path": "../../packages/models" },
{ "path": "../../packages/node-utils" },
{ "path": "../../packages/server-commands" }
]
}

View File

@ -3,7 +3,7 @@
"ignorePatterns": [ "ignorePatterns": [
"projects/**/*", "projects/**/*",
"node_modules/", "node_modules/",
"src/standalone/player/dist" "src/standalone/embed-player-api/dist"
], ],
"overrides": [ "overrides": [
{ {
@ -14,6 +14,7 @@
"project": [ "project": [
"tsconfig.eslint.json" "tsconfig.eslint.json"
], ],
"EXPERIMENTAL_useSourceOfProjectReferenceRedirect": true,
"createDefaultProgram": false "createDefaultProgram": false
}, },
"extends": [ "extends": [

4
client/.gitignore vendored
View File

@ -12,5 +12,5 @@
/e2e/local.log /e2e/local.log
/e2e/browserstack.err /e2e/browserstack.err
/e2e/screenshots /e2e/screenshots
/src/standalone/player/build /src/standalone/embed-player-api/build
/src/standalone/player/dist /src/standalone/embed-player-api/dist

View File

@ -195,11 +195,14 @@
"path-browserify", "path-browserify",
"deep-merge", "deep-merge",
"escape-string-regexp", "escape-string-regexp",
"mousetrap",
"is-plain-object", "is-plain-object",
"parse-srcset", "parse-srcset",
"deepmerge", "deepmerge",
"core-js/features/reflect" "core-js/features/reflect",
"@formatjs/intl-locale/polyfill",
"@formatjs/intl-locale/should-polyfill",
"@formatjs/intl-pluralrules/polyfill-force",
"@formatjs/intl-pluralrules/should-polyfill"
], ],
"scripts": [], "scripts": [],
"vendorChunk": true, "vendorChunk": true,

View File

@ -1,4 +1,4 @@
import { go } from '../utils' import { browserSleep, go, isAndroid } from '../utils'
export class LoginPage { export class LoginPage {
@ -23,12 +23,20 @@ export class LoginPage {
await $('input#username').setValue(username) await $('input#username').setValue(username)
await $('input#password').setValue(password) await $('input#password').setValue(password)
await browser.pause(1000) await browserSleep(1000)
await $('form input[type=submit]').click() const submit = $('.login-form-and-externals > form input[type=submit]')
await submit.click()
// Have to do this on Android, don't really know why
// I think we need to "escape" from the password input, so click twice on the submit button
if (isAndroid()) {
await browserSleep(2000)
await submit.click()
}
if (this.isMobileDevice) { if (this.isMobileDevice) {
const menuToggle = $('.top-left-block span[role=button]') const menuToggle = $('.top-left-block button')
await $('h2=Our content selection').waitForDisplayed() await $('h2=Our content selection').waitForDisplayed()
@ -79,7 +87,7 @@ export class LoginPage {
await logout.click() await logout.click()
await browser.waitUntil(() => { await browser.waitUntil(() => {
return $('.login-buttons-block, my-error-page a[href="/login"]').isDisplayed() return $$('.login-buttons-block, my-error-page a[href="/login"]').some(e => e.isDisplayed())
}) })
} }

View File

@ -1,4 +1,4 @@
import { getCheckbox, go } from '../utils' import { getCheckbox, go, selectCustomSelect } from '../utils'
export class MyAccountPage { export class MyAccountPage {
@ -117,6 +117,26 @@ export class MyAccountPage {
return go(url) return go(url)
} }
async updatePlaylistPrivacy (playlistUUID: string, privacy: 'Public' | 'Private' | 'Unlisted') {
go('/my-library/video-playlists/update/' + playlistUUID)
await browser.waitUntil(async () => {
return (await $('form .video-playlist-title').getText() === 'PLAYLIST')
})
await selectCustomSelect('videoChannelId', 'Main root channel')
await selectCustomSelect('privacy', privacy)
const submit = await $('form input[type=submit]')
await submit.waitForClickable()
await submit.scrollIntoView()
await submit.click()
return browser.waitUntil(async () => {
return (await browser.getUrl()).includes('my-library/video-playlists')
})
}
// My account Videos // My account Videos
private async getVideoElement (name: string) { private async getVideoElement (name: string) {

View File

@ -29,29 +29,34 @@ export class PlayerPage {
} }
async playAndPauseVideo (isAutoplay: boolean, waitUntilSec: number) { async playAndPauseVideo (isAutoplay: boolean, waitUntilSec: number) {
const videojsElem = () => $('div.video-js') // Autoplay is disabled on mobile and Safari
if (isIOS() || isSafari() || isMobileDevice() || isAutoplay === false) {
await videojsElem().waitForExist() await this.playVideo()
// Autoplay is disabled on iOS and Safari
if (isIOS() || isSafari() || isMobileDevice()) {
// We can't play the video if it is not muted
await browser.execute(`document.querySelector('video').muted = true`)
await this.clickOnPlayButton()
} else if (isAutoplay === false) {
await this.clickOnPlayButton()
} }
await $('div.video-js.vjs-has-started').waitForExist()
await browserSleep(2000) await browserSleep(2000)
await browser.waitUntil(async () => { await browser.waitUntil(async () => {
return (await this.getWatchVideoPlayerCurrentTime()) >= waitUntilSec return (await this.getWatchVideoPlayerCurrentTime()) >= waitUntilSec
}) }, { timeout: Math.max(waitUntilSec * 2 * 1000, 30000) })
await videojsElem().click() // Pause video
await $('div.video-js').click()
} }
async playVideo () { async playVideo () {
await $('div.video-js.vjs-paused, div.video-js.vjs-playing').waitForExist()
if (await $('div.video-js.vjs-playing').isExisting()) return
// Autoplay is disabled on iOS and Safari
if (isIOS() || isSafari() || isMobileDevice()) {
// We can't play the video if it is not muted
await browser.execute(`document.querySelector('video').muted = true`)
}
return this.clickOnPlayButton() return this.clickOnPlayButton()
} }
@ -61,4 +66,15 @@ export class PlayerPage {
await playButton().waitForClickable() await playButton().waitForClickable()
await playButton().click() await playButton().click()
} }
async fillEmbedVideoPassword (videoPassword: string) {
const videoPasswordInput = $('input#video-password-input')
const confirmButton = await $('button#video-password-submit')
await videoPasswordInput.clearValue()
await videoPasswordInput.setValue(videoPassword)
await confirmButton.waitForClickable()
return confirmButton.click()
}
} }

View File

@ -62,4 +62,26 @@ export class SignupPage {
await $('#displayName').setValue(options.displayName || `${options.name} channel display name`) await $('#displayName').setValue(options.displayName || `${options.name} channel display name`)
await $('#name').setValue(options.name) await $('#name').setValue(options.name)
} }
async fullSignup ({ accountInfo, channelInfo }: {
accountInfo: {
username: string
password?: string
displayName?: string
email?: string
}
channelInfo: {
name: string
}
}) {
await this.clickOnRegisterInMenu()
await this.validateStep()
await this.checkTerms()
await this.validateStep()
await this.fillAccountStep(accountInfo)
await this.validateStep()
await this.fillChannelStep(channelInfo)
await this.validateStep()
await this.getEndMessage()
}
} }

View File

@ -2,7 +2,7 @@ export class VideoSearchPage {
async search (search: string) { async search (search: string) {
await $('#search-video').setValue(search) await $('#search-video').setValue(search)
await $('my-header .icon-search').click() await $('.search-button').click()
await browser.waitUntil(() => { await browser.waitUntil(() => {
return $('my-video-miniature').isDisplayed() return $('my-video-miniature').isDisplayed()

View File

@ -64,6 +64,16 @@ export class VideoUploadPage {
return selectCustomSelect('privacy', 'Private') return selectCustomSelect('privacy', 'Private')
} }
async setAsPasswordProtected (videoPassword: string) {
selectCustomSelect('privacy', 'Password protected')
const videoPasswordInput = $('input#videoPassword')
await videoPasswordInput.waitForClickable()
await videoPasswordInput.clearValue()
return videoPasswordInput.setValue(videoPassword)
}
private getSecondStepSubmitButton () { private getSecondStepSubmitButton () {
return $('.submit-container my-button') return $('.submit-container my-button')
} }

View File

@ -9,11 +9,12 @@ export class VideoWatchPage {
waitWatchVideoName (videoName: string) { waitWatchVideoName (videoName: string) {
if (this.isSafari) return browserSleep(5000) if (this.isSafari) return browserSleep(5000)
// On mobile we display the first node, on desktop the second // On mobile we display the first node, on desktop the second one
const index = this.isMobileDevice ? 0 : 1 const index = this.isMobileDevice ? 0 : 1
return browser.waitUntil(async () => { return browser.waitUntil(async () => {
return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName) return await $('.video-info .video-info-name').isExisting() &&
(await $$('.video-info .video-info-name')[index].getText()).includes(videoName)
}) })
} }
@ -43,19 +44,25 @@ export class VideoWatchPage {
return $('my-privacy-concerns').isDisplayed() return $('my-privacy-concerns').isDisplayed()
} }
async goOnAssociatedEmbed () { async goOnAssociatedEmbed (passwordProtected = false) {
let url = await browser.getUrl() let url = await browser.getUrl()
url = url.replace('/w/', '/videos/embed/') url = url.replace('/w/', '/videos/embed/')
url = url.replace(':3333', ':9001') url = url.replace(':3333', ':9001')
await go(url) await go(url)
await this.waitEmbedForDisplayed()
if (passwordProtected) await this.waitEmbedForVideoPasswordForm()
else await this.waitEmbedForDisplayed()
} }
waitEmbedForDisplayed () { waitEmbedForDisplayed () {
return $('.vjs-big-play-button').waitForDisplayed() return $('.vjs-big-play-button').waitForDisplayed()
} }
waitEmbedForVideoPasswordForm () {
return $('#video-password-input').waitForDisplayed()
}
isEmbedWarningDisplayed () { isEmbedWarningDisplayed () {
return $('.peertube-dock-description').isDisplayed() return $('.peertube-dock-description').isDisplayed()
} }
@ -138,4 +145,78 @@ export class VideoWatchPage {
return elem() return elem()
} }
isPasswordProtected () {
return $('#confirmInput').isExisting()
}
async fillVideoPassword (videoPassword: string) {
const videoPasswordInput = await $('input#confirmInput')
await videoPasswordInput.waitForClickable()
await videoPasswordInput.clearValue()
await videoPasswordInput.setValue(videoPassword)
const confirmButton = await $('input[value="Confirm"]')
await confirmButton.waitForClickable()
return confirmButton.click()
}
async like () {
const likeButton = await $('.action-button-like')
const isActivated = (await likeButton.getAttribute('class')).includes('activated')
let count: number
try {
count = parseInt(await $('.action-button-like > .count').getText())
} catch (error) {
count = 0
}
await likeButton.waitForClickable()
await likeButton.click()
if (isActivated) {
if (count === 1) {
return expect(!await $('.action-button-like > .count').isExisting())
} else {
return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count - 1)
}
} else {
return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count + 1)
}
}
async createThread (comment: string) {
const textarea = await $('my-video-comment-add textarea')
await textarea.waitForClickable()
await textarea.setValue(comment)
const confirmButton = await $('.comment-buttons .orange-button')
await confirmButton.waitForClickable()
await confirmButton.click()
const createdComment = await (await $('.comment-html p')).getText()
return expect(createdComment).toBe(comment)
}
async createReply (comment: string) {
const replyButton = await $('button.comment-action-reply')
await replyButton.waitForClickable()
await replyButton.scrollIntoView()
await replyButton.click()
const textarea = await $('my-video-comment my-video-comment-add textarea')
await textarea.waitForClickable()
await textarea.setValue(comment)
const confirmButton = await $('my-video-comment .comment-buttons .orange-button')
await confirmButton.waitForClickable()
await confirmButton.click()
const createdComment = await (await $('.is-child .comment-html p')).getText()
return expect(createdComment).toBe(comment)
}
} }

View File

@ -31,8 +31,8 @@ describe('Private videos all workflow', () => {
return loginPage.loginOnPeerTube2() return loginPage.loginOnPeerTube2()
}) })
it('Should play an internal webtorrent video', async () => { it('Should play an internal web video', async () => {
await go(FIXTURE_URLS.INTERNAL_WEBTORRENT_VIDEO) await go(FIXTURE_URLS.INTERNAL_WEB_VIDEO)
await videoWatchPage.waitWatchVideoName(internalVideoName) await videoWatchPage.waitWatchVideoName(internalVideoName)
await checkCorrectlyPlay(playerPage) await checkCorrectlyPlay(playerPage)
@ -52,8 +52,8 @@ describe('Private videos all workflow', () => {
await checkCorrectlyPlay(playerPage) await checkCorrectlyPlay(playerPage)
}) })
it('Should play an internal WebTorrent video in embed', async () => { it('Should play an internal Web Video in embed', async () => {
await go(FIXTURE_URLS.INTERNAL_EMBED_WEBTORRENT_VIDEO) await go(FIXTURE_URLS.INTERNAL_EMBED_WEB_VIDEO)
await videoWatchPage.waitEmbedForDisplayed() await videoWatchPage.waitEmbedForDisplayed()
await checkCorrectlyPlay(playerPage) await checkCorrectlyPlay(playerPage)

View File

@ -89,7 +89,7 @@ describe('Videos all workflow', () => {
let videoNameToExcept = videoName let videoNameToExcept = videoName
if (isMobileDevice() || isSafari()) { if (isMobileDevice() || isSafari()) {
await go(FIXTURE_URLS.WEBTORRENT_VIDEO) await go(FIXTURE_URLS.WEB_VIDEO)
videoNameToExcept = 'E2E tests' videoNameToExcept = 'E2E tests'
} else { } else {
await videoListPage.clickOnVideo(videoName) await videoListPage.clickOnVideo(videoName)
@ -176,7 +176,7 @@ describe('Videos all workflow', () => {
await videoWatchPage.waitUntilVideoName(video2Name, 40 * 1000) await videoWatchPage.waitUntilVideoName(video2Name, 40 * 1000)
}) })
it('Should watch the webtorrent playlist in the embed', async () => { it('Should watch the WEB VIDEO playlist in the embed', async () => {
if (isUploadUnsupported()) return if (isUploadUnsupported()) return
const accessToken = await browser.execute(`return window.localStorage.getItem('access_token');`) const accessToken = await browser.execute(`return window.localStorage.getItem('access_token');`)

View File

@ -1,7 +1,7 @@
import { LoginPage } from '../po/login.po' import { LoginPage } from '../po/login.po'
import { VideoUploadPage } from '../po/video-upload.po' import { VideoUploadPage } from '../po/video-upload.po'
import { VideoWatchPage } from '../po/video-watch.po' import { VideoWatchPage } from '../po/video-watch.po'
import { go, isMobileDevice, isSafari, waitServerUp } from '../utils' import { getScreenshotPath, go, isMobileDevice, isSafari, waitServerUp } from '../utils'
describe('Custom server defaults', () => { describe('Custom server defaults', () => {
let videoUploadPage: VideoUploadPage let videoUploadPage: VideoUploadPage
@ -83,4 +83,8 @@ describe('Custom server defaults', () => {
await checkP2P(false) await checkP2P(false)
}) })
}) })
after(async () => {
await browser.saveScreenshot(getScreenshotPath('after-test.png'))
})
}) })

View File

@ -35,7 +35,7 @@ function checkEndMessage (options: {
} }
{ {
const checkEmail = 'Check your emails' const checkEmail = 'Check your email'
if (requiresEmailVerification) { if (requiresEmailVerification) {
expect(message).toContain(checkEmail) expect(message).toContain(checkEmail)

View File

@ -0,0 +1,229 @@
import { LoginPage } from '../po/login.po'
import { SignupPage } from '../po/signup.po'
import { PlayerPage } from '../po/player.po'
import { VideoUploadPage } from '../po/video-upload.po'
import { VideoWatchPage } from '../po/video-watch.po'
import { getScreenshotPath, go, isMobileDevice, isSafari, waitServerUp } from '../utils'
import { MyAccountPage } from '../po/my-account.po'
describe('Password protected videos', () => {
let videoUploadPage: VideoUploadPage
let loginPage: LoginPage
let videoWatchPage: VideoWatchPage
let signupPage: SignupPage
let playerPage: PlayerPage
let myAccountPage: MyAccountPage
let passwordProtectedVideoUrl: string
let playlistUrl: string
const seed = Math.random()
const passwordProtectedVideoName = seed + ' - password protected'
const publicVideoName1 = seed + ' - public 1'
const publicVideoName2 = seed + ' - public 2'
const videoPassword = 'password'
const regularUsername = 'user_1'
const regularUserPassword = 'user password'
const playlistName = seed + ' - playlist'
function testRateAndComment () {
it('Should add and remove like on video', async function () {
await videoWatchPage.like()
await videoWatchPage.like()
})
it('Should create thread on video', async function () {
await videoWatchPage.createThread('My first comment')
})
it('Should reply to thread on video', async function () {
await videoWatchPage.createReply('My first reply')
})
}
before(async () => {
await waitServerUp()
loginPage = new LoginPage(isMobileDevice())
videoUploadPage = new VideoUploadPage()
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
signupPage = new SignupPage()
playerPage = new PlayerPage()
myAccountPage = new MyAccountPage()
await browser.maximizeWindow()
})
describe('Owner', function () {
before(async () => {
await loginPage.loginAsRootUser()
})
it('Should login, upload a public video and save it to a playlist', async () => {
await videoUploadPage.navigateTo()
await videoUploadPage.uploadVideo('video.mp4')
await videoUploadPage.validSecondUploadStep(publicVideoName1)
await videoWatchPage.clickOnSave()
await videoWatchPage.createPlaylist(playlistName)
await videoWatchPage.saveToPlaylist(playlistName)
await browser.pause(5000)
})
it('Should upload a password protected video', async () => {
await videoUploadPage.navigateTo()
await videoUploadPage.uploadVideo('video2.mp4')
await videoUploadPage.setAsPasswordProtected(videoPassword)
await videoUploadPage.validSecondUploadStep(passwordProtectedVideoName)
await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
passwordProtectedVideoUrl = await browser.getUrl()
})
it('Should save to playlist the password protected video', async () => {
await videoWatchPage.clickOnSave()
await videoWatchPage.saveToPlaylist(playlistName)
})
it('Should upload a second public video and save it to playlist', async () => {
await videoUploadPage.navigateTo()
await videoUploadPage.uploadVideo('video3.mp4')
await videoUploadPage.validSecondUploadStep(publicVideoName2)
await videoWatchPage.clickOnSave()
await videoWatchPage.saveToPlaylist(playlistName)
})
it('Should play video without password', async function () {
await go(passwordProtectedVideoUrl)
expect(!await videoWatchPage.isPasswordProtected())
await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
await playerPage.playAndPauseVideo(false, 2)
})
testRateAndComment()
it('Should play video on embed without password', async function () {
await videoWatchPage.goOnAssociatedEmbed()
await playerPage.playAndPauseVideo(false, 2)
})
it('Should have the playlist in my account', async function () {
await go('/')
await myAccountPage.navigateToMyPlaylists()
const videosNumberText = await myAccountPage.getPlaylistVideosText(playlistName)
expect(videosNumberText).toEqual('3 videos')
await myAccountPage.clickOnPlaylist(playlistName)
const count = await myAccountPage.countTotalPlaylistElements()
expect(count).toEqual(3)
})
it('Should update the playlist to public', async () => {
const url = await browser.getUrl()
const regex = /\/([a-f0-9-]+)$/i
const match = url.match(regex)
const uuid = match ? match[1] : null
await myAccountPage.updatePlaylistPrivacy(uuid, 'Public')
})
it('Should watch the playlist', async () => {
await myAccountPage.clickOnPlaylist(playlistName)
await myAccountPage.playPlaylist()
playlistUrl = await browser.getUrl()
await videoWatchPage.waitUntilVideoName(publicVideoName1, 40 * 1000)
await videoWatchPage.waitUntilVideoName(passwordProtectedVideoName, 40 * 1000)
await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
})
after(async () => {
await loginPage.logout()
})
})
describe('Regular users', function () {
before(async () => {
await signupPage.fullSignup({
accountInfo: {
username: regularUsername,
password: regularUserPassword
},
channelInfo: {
name: 'user_1_channel'
}
})
})
it('Should requires password to play video', async function () {
await go(passwordProtectedVideoUrl)
expect(await videoWatchPage.isPasswordProtected())
await videoWatchPage.fillVideoPassword(videoPassword)
await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
await playerPage.playAndPauseVideo(true, 2)
})
testRateAndComment()
it('Should requires password to play video on embed', async function () {
await videoWatchPage.goOnAssociatedEmbed(true)
await playerPage.fillEmbedVideoPassword(videoPassword)
await playerPage.playAndPauseVideo(false, 2)
})
it('Should watch the playlist without password protected video', async () => {
await go(playlistUrl)
await playerPage.playVideo()
await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
})
after(async () => {
await loginPage.logout()
})
})
describe('Anonymous users', function () {
it('Should requires password to play video', async function () {
await go(passwordProtectedVideoUrl)
expect(await videoWatchPage.isPasswordProtected())
await videoWatchPage.fillVideoPassword(videoPassword)
await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
await playerPage.playAndPauseVideo(true, 2)
})
it('Should requires password to play video on embed', async function () {
await videoWatchPage.goOnAssociatedEmbed(true)
await playerPage.fillEmbedVideoPassword(videoPassword)
await playerPage.playAndPauseVideo(false, 2)
})
it('Should watch the playlist without password protected video', async () => {
await go(playlistUrl)
await playerPage.playVideo()
await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
})
})
after(async () => {
await browser.saveScreenshot(getScreenshotPath('after-test.png'))
})
})

View File

@ -8,6 +8,12 @@ function isMobileDevice () {
return platformName === 'android' || platformName === 'ios' return platformName === 'android' || platformName === 'ios'
} }
function isAndroid () {
const platformName = (browser.capabilities['platformName'] || '').toLowerCase()
return platformName === 'android'
}
function isSafari () { function isSafari () {
return browser.capabilities['browserName'] && return browser.capabilities['browserName'] &&
browser.capabilities['browserName'].toLowerCase() === 'safari' browser.capabilities['browserName'].toLowerCase() === 'safari'
@ -20,7 +26,6 @@ function isIOS () {
async function go (url: string) { async function go (url: string) {
await browser.url(url) await browser.url(url)
// Hide notifications that could fail tests when hiding buttons
await browser.execute(() => { await browser.execute(() => {
const style = document.createElement('style') const style = document.createElement('style')
style.innerHTML = 'p-toast { display: none }' style.innerHTML = 'p-toast { display: none }'
@ -41,6 +46,7 @@ export {
isMobileDevice, isMobileDevice,
isSafari, isSafari,
isIOS, isIOS,
isAndroid,
waitServerUp, waitServerUp,
go, go,
browserSleep browserSleep

View File

@ -93,5 +93,14 @@ function buildConfig (suiteFile: string = undefined) {
} }
} }
if (filename === 'video-password.e2e-spec.ts') {
return {
signup: {
enabled: true,
limit: -1
}
}
}
return {} return {}
} }

View File

@ -3,6 +3,8 @@ import { join, resolve } from 'path'
function runServer (appInstance: number, config: any = {}) { function runServer (appInstance: number, config: any = {}) {
const env = Object.create(process.env) const env = Object.create(process.env)
env['NODE_OPTIONS'] = ''
env['NODE_ENV'] = 'test' env['NODE_ENV'] = 'test'
env['NODE_APP_INSTANCE'] = appInstance + '' env['NODE_APP_INSTANCE'] = appInstance + ''
@ -43,7 +45,10 @@ function runServer (appInstance: number, config: any = {}) {
function runCommand (command: string) { function runCommand (command: string) {
return new Promise<void>((res, rej) => { return new Promise<void>((res, rej) => {
const p = exec(command, { cwd: getRootCWD() }) // Reset NODE_OPTIONS env set by webdriverio
const env = { ...process.env, NODE_OPTIONS: '' }
const p = exec(command, { env, cwd: getRootCWD() })
p.stderr.on('data', data => console.error(data.toString())) p.stderr.on('data', data => console.error(data.toString()))
p.on('error', err => rej(err)) p.on('error', err => rej(err))

View File

@ -1,14 +1,14 @@
const FIXTURE_URLS = { const FIXTURE_URLS = {
INTERNAL_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0', INTERNAL_WEB_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?mode=web-video&start=0',
INTERNAL_HLS_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?start=0', INTERNAL_HLS_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?start=0',
INTERNAL_EMBED_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0', INTERNAL_EMBED_WEB_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?mode=web-video&start=0',
INTERNAL_EMBED_HLS_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?start=0', INTERNAL_EMBED_HLS_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?start=0',
INTERNAL_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/w/tKQmHcqdYZRdCszLUiWM3V?start=0', INTERNAL_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/w/tKQmHcqdYZRdCszLUiWM3V?start=0',
INTERNAL_EMBED_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/videos/embed/tKQmHcqdYZRdCszLUiWM3V?start=0', INTERNAL_EMBED_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/videos/embed/tKQmHcqdYZRdCszLUiWM3V?start=0',
WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e', WEB_VIDEO: 'https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e',
HLS_EMBED: 'https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50', HLS_EMBED: 'https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50',
HLS_PLAYLIST_EMBED: 'https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a', HLS_PLAYLIST_EMBED: 'https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a',

View File

@ -6,6 +6,10 @@
"esModuleInterop": true, "esModuleInterop": true,
"module": "commonjs", "module": "commonjs",
"target": "es5", "target": "es5",
"typeRoots": [
"../node_modules/@types",
"../node_modules"
],
"types": [ "types": [
"node", "node",
"@wdio/globals/types", "@wdio/globals/types",

View File

@ -17,18 +17,32 @@ function buildMainOptions (sessionName: string) {
} }
} }
function buildBStackDesktopOptions (sessionName: string, resolution: string, os?: string) { function buildBStackDesktopOptions (options: {
sessionName: string
resolution: string
os?: string
osVersion?: string
}) {
const { sessionName, resolution, os, osVersion } = options
return { return {
'bstack:options': { 'bstack:options': {
...buildMainOptions(sessionName), ...buildMainOptions(sessionName),
os, os,
osVersion,
resolution resolution
} }
} }
} }
function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string) { function buildBStackMobileOptions (options: {
sessionName: string
deviceName: string
osVersion: string
}) {
const { sessionName, deviceName, osVersion } = options
return { return {
'bstack:options': { 'bstack:options': {
...buildMainOptions(sessionName), ...buildMainOptions(sessionName),
@ -53,45 +67,45 @@ module.exports = {
{ {
browserName: 'Chrome', browserName: 'Chrome',
...buildBStackDesktopOptions('Latest Chrome Desktop', '1280x1024') ...buildBStackDesktopOptions({ sessionName: 'Latest Chrome Desktop', resolution: '1280x1024', os: 'Windows', osVersion: '8' })
}, },
{ {
browserName: 'Firefox', browserName: 'Firefox',
browserVersion: '78', // Very old ESR browserVersion: '78', // Very old ESR
...buildBStackDesktopOptions('Firefox ESR Desktop', '1280x1024', 'Windows') ...buildBStackDesktopOptions({ sessionName: 'Firefox ESR Desktop', resolution: '1280x1024', os: 'Windows', osVersion: '8' })
}, },
{ {
browserName: 'Safari', browserName: 'Safari',
browserVersion: '12.1', browserVersion: '12.1',
...buildBStackDesktopOptions('Safari Desktop', '1280x1024') ...buildBStackDesktopOptions({ sessionName: 'Safari Desktop', resolution: '1280x1024' })
}, },
{ {
browserName: 'Firefox', browserName: 'Firefox',
...buildBStackDesktopOptions('Firefox Latest', '1280x1024') ...buildBStackDesktopOptions({ sessionName: 'Firefox Latest', resolution: '1280x1024', os: 'Windows', osVersion: '8' })
}, },
{ {
browserName: 'Edge', browserName: 'Edge',
...buildBStackDesktopOptions('Edge Latest', '1280x1024') ...buildBStackDesktopOptions({ sessionName: 'Edge Latest', resolution: '1280x1024' })
}, },
{ {
browserName: 'Chrome', browserName: 'Chrome',
...buildBStackMobileOptions('Latest Chrome Android', 'Samsung Galaxy S8', '7.0') ...buildBStackMobileOptions({ sessionName: 'Latest Chrome Android', deviceName: 'Samsung Galaxy S8', osVersion: '7.0' })
}, },
{ {
browserName: 'Safari', browserName: 'Safari',
...buildBStackMobileOptions('Safari iPhone', 'iPhone 8 Plus', '12.4') ...buildBStackMobileOptions({ sessionName: 'Safari iPhone', deviceName: 'iPhone 8 Plus', osVersion: '12.4' })
}, },
{ {
browserName: 'Safari', browserName: 'Safari',
...buildBStackMobileOptions('Safari iPad', 'iPad 7th', '13') ...buildBStackMobileOptions({ sessionName: 'Safari iPad', deviceName: 'iPad 7th', osVersion: '13' })
} }
], ],

View File

@ -28,7 +28,7 @@ module.exports = {
'browserName': 'chrome', 'browserName': 'chrome',
'acceptInsecureCerts': true, 'acceptInsecureCerts': true,
'goog:chromeOptions': { 'goog:chromeOptions': {
args: [ '--disable-gpu', windowSizeArg ], args: [ '--headless', '--disable-gpu', windowSizeArg ],
prefs prefs
} }
}, },
@ -43,7 +43,7 @@ module.exports = {
} }
], ],
services: [ 'chromedriver', 'geckodriver', 'shared-store' ], services: [ 'shared-store' ],
beforeSession: beforeLocalSession, beforeSession: beforeLocalSession,
beforeSuite: beforeLocalSuite, beforeSuite: beforeLocalSuite,

View File

@ -22,6 +22,7 @@ module.exports = {
{ {
'browserName': 'chrome', 'browserName': 'chrome',
'goog:chromeOptions': { 'goog:chromeOptions': {
binary: '/usr/bin/google-chrome-stable',
args: [ '--headless', '--disable-gpu', windowSizeArg ], args: [ '--headless', '--disable-gpu', windowSizeArg ],
prefs prefs
} }
@ -37,7 +38,7 @@ module.exports = {
} }
], ],
services: [ 'chromedriver', 'geckodriver', 'shared-store' ], services: [ 'shared-store' ],
beforeSession: beforeLocalSession, beforeSession: beforeLocalSession,
beforeSuite: beforeLocalSuite, beforeSuite: beforeLocalSuite,

View File

@ -59,7 +59,7 @@ export const config = {
// with `/`, the base url gets prepended, not including the path portion of your baseUrl. // with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly. // gets prepended directly.
baseUrl: 'http://localhost:9001', baseUrl: 'http://127.0.0.1:9001',
// //
// Default timeout for all waitFor* commands. // Default timeout for all waitFor* commands.
waitforTimeout: 5000, waitforTimeout: 5000,
@ -80,7 +80,7 @@ export const config = {
framework: 'mocha', framework: 'mocha',
// //
// The number of times to retry the entire specfile when it fails as a whole // The number of times to retry the entire specfile when it fails as a whole
specFileRetries: 1, specFileRetries: 2,
// //
// Delay in seconds between the spec file retry attempts // Delay in seconds between the spec file retry attempts
// specFileRetriesDelay: 0, // specFileRetriesDelay: 0,
@ -107,14 +107,6 @@ export const config = {
tsNodeOpts: { tsNodeOpts: {
project: require('path').join(__dirname, './tsconfig.json') project: require('path').join(__dirname, './tsconfig.json')
},
tsConfigPathsOpts: {
baseUrl: './',
paths: {
'@server/*': [ '../../server/*' ],
'@shared/*': [ '../../shared/*' ]
}
} }
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "peertube-client", "name": "peertube-client",
"version": "5.2.1", "version": "6.0.1",
"private": true, "private": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"author": { "author": {
@ -14,7 +14,7 @@
}, },
"scripts": { "scripts": {
"lint": "npm run lint-ts && npm run lint-scss", "lint": "npm run lint-ts && npm run lint-scss",
"lint-ts": "eslint --ext .ts src/standalone/**/*.ts && npm run ng lint", "lint-ts": "eslint --cache --ext .ts src/standalone/**/*.ts && npm run ng lint",
"lint-scss": "stylelint 'src/**/*.scss'", "lint-scss": "stylelint 'src/**/*.scss'",
"webpack": "webpack", "webpack": "webpack",
"eslint": "eslint", "eslint": "eslint",
@ -24,6 +24,9 @@
"ngx-extractor": "ngx-extractor", "ngx-extractor": "ngx-extractor",
"stylelint": "stylelint" "stylelint": "stylelint"
}, },
"workspaces": [
"../packages/*"
],
"typings": "*.d.ts", "typings": "*.d.ts",
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^16.0.2", "@angular-devkit/build-angular": "^16.0.2",
@ -47,14 +50,18 @@
"@angular/service-worker": "^16.0.2", "@angular/service-worker": "^16.0.2",
"@babel/core": "^7.18.5", "@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2", "@babel/preset-env": "^7.18.2",
"@ng-bootstrap/ng-bootstrap": "^14.0.1", "@formatjs/intl-locale": "^3.3.1",
"@ng-select/ng-select": "^10.0.3", "@formatjs/intl-pluralrules": "^5.2.2",
"@ng-bootstrap/ng-bootstrap": "^15.1.1",
"@ng-select/ng-select": "^11.2.0",
"@ngx-loading-bar/core": "^6.0.0", "@ngx-loading-bar/core": "^6.0.0",
"@ngx-loading-bar/http-client": "^6.0.0", "@ngx-loading-bar/http-client": "^6.0.0",
"@ngx-loading-bar/router": "^6.0.0", "@ngx-loading-bar/router": "^6.0.0",
"@peertube/maildev": "^1.2.0", "@peertube/maildev": "^1.2.0",
"@peertube/p2p-media-loader-core": "^1.0.14", "@peertube/p2p-media-loader-core": "^1.0.15",
"@peertube/p2p-media-loader-hlsjs": "^1.0.14", "@peertube/p2p-media-loader-hlsjs": "^1.0.15",
"@peertube/peertube-core-utils": "*",
"@peertube/peertube-models": "*",
"@peertube/videojs-contextmenu": "^5.5.0", "@peertube/videojs-contextmenu": "^5.5.0",
"@peertube/xliffmerge": "^2.0.3", "@peertube/xliffmerge": "^2.0.3",
"@popperjs/core": "^2.11.5", "@popperjs/core": "^2.11.5",
@ -64,58 +71,48 @@
"@types/jschannel": "^1.0.0", "@types/jschannel": "^1.0.0",
"@types/linkifyjs": "^2.1.2", "@types/linkifyjs": "^2.1.2",
"@types/lodash-es": "^4.17.0", "@types/lodash-es": "^4.17.0",
"@types/markdown-it": "^12.0.1", "@types/markdown-it": "^13.0.2",
"@types/node": "^18.13.0", "@types/node": "^18.13.0",
"@types/sanitize-html": "2.6.2", "@types/sanitize-html": "2.9.2",
"@types/sha.js": "^2.4.0", "@types/sha.js": "^2.4.0",
"@types/video.js": "^7.3.40", "@types/video.js": "^7.3.40",
"@types/webtorrent": "^0.109.0", "@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^6.7.5",
"@typescript-eslint/parser": "^5.43.0",
"@wdio/browserstack-service": "^8.10.5", "@wdio/browserstack-service": "^8.10.5",
"@wdio/cli": "^8.10.5", "@wdio/cli": "^8.10.5",
"@wdio/local-runner": "^8.10.5", "@wdio/local-runner": "^8.10.5",
"@wdio/mocha-framework": "^8.10.4", "@wdio/mocha-framework": "^8.10.4",
"@wdio/shared-store-service": "^8.10.5", "@wdio/shared-store-service": "^8.10.5",
"@wdio/spec-reporter": "^8.10.5", "@wdio/spec-reporter": "^8.10.5",
"angular2-hotkeys": "^13.1.0",
"angularx-qrcode": "16.0.0", "angularx-qrcode": "16.0.0",
"babel-loader": "^9.1.0", "babel-loader": "^9.1.0",
"bootstrap": "^5.1.3", "bootstrap": "^5.1.3",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"cache-chunk-store": "^3.0.0",
"chart.js": "^4.3.0", "chart.js": "^4.3.0",
"chartjs-plugin-zoom": "~2.0.1", "chartjs-plugin-zoom": "~2.0.1",
"chromedriver": "^113.0.0",
"core-js": "^3.22.8", "core-js": "^3.22.8",
"css-loader": "^6.2.0", "css-loader": "^6.2.0",
"debug": "^4.3.1", "debug": "^4.3.1",
"dexie": "^3.2.2",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.28.1",
"eslint-plugin-jsdoc": "^44.2.4", "eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-prefer-arrow": "latest", "eslint-plugin-prefer-arrow": "latest",
"expect-webdriverio": "^4.2.3", "expect-webdriverio": "^4.2.3",
"focus-visible": "^5.0.2", "focus-visible": "^5.0.2",
"geckodriver": "^4.0.0",
"hls.js": "~1.3", "hls.js": "~1.3",
"html-loader": "^4.1.0", "html-loader": "^4.1.0",
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"https-browserify": "^1.0.0",
"intl-messageformat": "^10.1.0", "intl-messageformat": "^10.1.0",
"jschannel": "^1.0.2", "jschannel": "^1.0.2",
"linkify-html": "^4.0.2", "linkify-html": "^4.0.2",
"linkifyjs": "^4.0.2", "linkifyjs": "^4.0.2",
"lodash-es": "^4.17.4", "lodash-es": "^4.17.4",
"markdown-it": "13.0.1", "markdown-it": "13.0.2",
"mini-css-extract-plugin": "^2.2.0", "mini-css-extract-plugin": "^2.2.0",
"ngx-uploadx": "^6.1.0", "ngx-uploadx": "^6.1.0",
"path-browserify": "^1.0.0", "path-browserify": "^1.0.0",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"primeng": "^16.0.0-rc.2", "primeng": "^16.0.0-rc.2",
"process": "^0.11.10",
"purify-css": "^1.2.5",
"querystring": "^0.2.1",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"rxjs": "^7.3.0", "rxjs": "^7.3.0",
"sanitize-html": "^2.1.2", "sanitize-html": "^2.1.2",
@ -123,23 +120,17 @@
"sass-loader": "^13.2.0", "sass-loader": "^13.2.0",
"sha.js": "^2.4.11", "sha.js": "^2.4.11",
"socket.io-client": "^4.5.4", "socket.io-client": "^4.5.4",
"stream-browserify": "^3.0.0",
"stream-http": "^3.0.0",
"stylelint": "^15.1.0", "stylelint": "^15.1.0",
"stylelint-config-sass-guidelines": "^10.0.0", "stylelint-config-sass-guidelines": "^10.0.0",
"tinykeys": "^2.1.0",
"ts-loader": "^9.3.0", "ts-loader": "^9.3.0",
"ts-node": "^10.9.1",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"typescript": "~4.9.5", "typescript": "~5.1.0",
"url": "^0.11.0",
"video.js": "^7.19.2", "video.js": "^7.19.2",
"videostream": "~3.2.1",
"wdio-chromedriver-service": "^8.1.1",
"wdio-geckodriver-service": "^5.0.1",
"webpack": "^5.73.0", "webpack": "^5.73.0",
"webpack-bundle-analyzer": "^4.4.2", "webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^5.0.1", "webpack-cli": "^5.0.1",
"webtorrent": "1.8.26",
"whatwg-fetch": "^3.0.0",
"zone.js": "~0.13.0" "zone.js": "~0.13.0"
}, },
"dependencies": {} "dependencies": {}

View File

@ -2,7 +2,7 @@ import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ComponentPagination, hasMoreItems, Notifier, RestService, ServerService } from '@app/core' import { ComponentPagination, hasMoreItems, Notifier, RestService, ServerService } from '@app/core'
import { InstanceFollowService } from '@app/shared/shared-instance' import { InstanceFollowService } from '@app/shared/shared-instance'
import { Actor } from '@shared/models/actors' import { Actor } from '@peertube/peertube-models'
@Component({ @Component({
selector: 'my-about-follows', selector: 'my-about-follows',

View File

@ -3,8 +3,8 @@ import { AfterViewChecked, Component, ElementRef, OnInit, ViewChild } from '@ang
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { Notifier, ServerService } from '@app/core' import { Notifier, ServerService } from '@app/core'
import { AboutHTML } from '@app/shared/shared-instance' import { AboutHTML } from '@app/shared/shared-instance'
import { HTMLServerConfig, ServerStats } from '@peertube/peertube-models'
import { copyToClipboard } from '@root-helpers/utils' import { copyToClipboard } from '@root-helpers/utils'
import { HTMLServerConfig, ServerStats } from '@shared/models/server'
import { ResolverData } from './about-instance.resolver' import { ResolverData } from './about-instance.resolver'
import { ContactAdminModalComponent } from './contact-admin-modal.component' import { ContactAdminModalComponent } from './contact-admin-modal.component'

View File

@ -4,7 +4,7 @@ import { Injectable } from '@angular/core'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { CustomMarkupService } from '@app/shared/shared-custom-markup' import { CustomMarkupService } from '@app/shared/shared-custom-markup'
import { AboutHTML, InstanceService } from '@app/shared/shared-instance' import { AboutHTML, InstanceService } from '@app/shared/shared-instance'
import { About, ServerStats } from '@shared/models/server' import { About, ServerStats } from '@peertube/peertube-models'
export type ResolverData = { export type ResolverData = {
serverStats: ServerStats serverStats: ServerStats

View File

@ -1,7 +1,10 @@
<ng-template #modal> <ng-template #modal>
<div class="modal-header"> <div class="modal-header">
<h1 i18n class="modal-title">Contact the administrator(s)<p class="modal-subtitle">{{ instanceName }}</p></h1> <h1 i18n class="modal-title">Contact the administrator(s)<p class="modal-subtitle">{{ instanceName }}</p></h1>
<my-global-icon iconName="cross" aria-label="Close" tabindex="0" role="button" (click)="hide()" (keydown.enter)="hide()"></my-global-icon>
<button class="border-0 p-0" title="Close this modal" i18n-title (click)="hide()">
<my-global-icon iconName="cross"></my-global-icon>
</button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -12,8 +15,9 @@
<input <input
type="text" id="fromName" class="form-control" type="text" id="fromName" class="form-control"
formControlName="fromName" [ngClass]="{ 'input-error': formErrors.fromName }" formControlName="fromName" [ngClass]="{ 'input-error': formErrors.fromName }"
autocomplete="name"
> >
<div *ngIf="formErrors.fromName" class="form-error">{{ formErrors.fromName }}</div> <div *ngIf="formErrors.fromName" class="form-error" role="alert">{{ formErrors.fromName }}</div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -21,8 +25,9 @@
<input <input
type="text" id="fromEmail" class="form-control" type="text" id="fromEmail" class="form-control"
formControlName="fromEmail" [ngClass]="{ 'input-error': formErrors['fromEmail'] }" formControlName="fromEmail" [ngClass]="{ 'input-error': formErrors['fromEmail'] }"
i18n-placeholder placeholder="Example: john@example.com" autocomplete="email"
> >
<div *ngIf="formErrors.fromEmail" class="form-error">{{ formErrors.fromEmail }}</div> <div *ngIf="formErrors.fromEmail" class="form-error" role="alert">{{ formErrors.fromEmail }}</div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -31,14 +36,14 @@
type="text" id="subject" class="form-control" type="text" id="subject" class="form-control"
formControlName="subject" [ngClass]="{ 'input-error': formErrors['subject'] }" formControlName="subject" [ngClass]="{ 'input-error': formErrors['subject'] }"
> >
<div *ngIf="formErrors.subject" class="form-error">{{ formErrors.subject }}</div> <div *ngIf="formErrors.subject" class="form-error" role="alert">{{ formErrors.subject }}</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label i18n for="body">Your message</label> <label i18n for="body">Your message</label>
<textarea id="body" formControlName="body" class="form-control" [ngClass]="{ 'input-error': formErrors['body'] }"> <textarea id="body" formControlName="body" class="form-control" [ngClass]="{ 'input-error': formErrors['body'] }">
</textarea> </textarea>
<div *ngIf="formErrors.body" class="form-error">{{ formErrors.body }}</div> <div *ngIf="formErrors.body" class="form-error" role="alert">{{ formErrors.body }}</div>
</div> </div>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <div *ngIf="error" class="alert alert-danger">{{ error }}</div>

View File

@ -11,7 +11,7 @@ import { FormReactive, FormReactiveService } from '@app/shared/shared-forms'
import { InstanceService } from '@app/shared/shared-instance' import { InstanceService } from '@app/shared/shared-instance'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { HTMLServerConfig, HttpStatusCode } from '@shared/models' import { HTMLServerConfig, HttpStatusCode } from '@peertube/peertube-models'
type Prefill = { type Prefill = {
subject?: string subject?: string

View File

@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { ServerStats } from '@shared/models/server' import { ServerStats } from '@peertube/peertube-models'
@Component({ @Component({
selector: 'my-instance-statistics', selector: 'my-instance-statistics',

View File

@ -2,10 +2,10 @@ import { from, Subject, Subscription } from 'rxjs'
import { concatMap, map, switchMap, tap } from 'rxjs/operators' import { concatMap, map, switchMap, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { ComponentPagination, hasMoreItems, MarkdownService, User, UserService } from '@app/core' import { ComponentPagination, hasMoreItems, MarkdownService, User, UserService } from '@app/core'
import { SimpleMemoize } from '@app/helpers'
import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main' import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature'
import { NSFWPolicyType, VideoSortField } from '@shared/models' import { NSFWPolicyType, VideoSortField } from '@peertube/peertube-models'
import { SimpleMemoize } from '@app/helpers'
@Component({ @Component({
selector: 'my-account-video-channels', selector: 'my-account-video-channels',
@ -98,7 +98,7 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
videoChannel, videoChannel,
videoPagination: this.videosPagination, videoPagination: this.videosPagination,
sort: this.videosSort, sort: this.videosSort,
nsfwPolicy: this.nsfwPolicy nsfw: this.videoService.nsfwPolicyToParam(this.nsfwPolicy)
} }
return this.videoService.getVideoChannelVideos(options) return this.videoService.getVideoChannelVideos(options)

View File

@ -4,7 +4,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
import { ComponentPaginationLight, DisableForReuseHook, ScreenService } from '@app/core' import { ComponentPaginationLight, DisableForReuseHook, ScreenService } from '@app/core'
import { Account, AccountService, VideoService } from '@app/shared/shared-main' import { Account, AccountService, VideoService } from '@app/shared/shared-main'
import { VideoFilters } from '@app/shared/shared-video-miniature' import { VideoFilters } from '@app/shared/shared-video-miniature'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@peertube/peertube-models'
@Component({ @Component({
selector: 'my-account-videos', selector: 'my-account-videos',

View File

@ -18,18 +18,18 @@
(userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()" (userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
></my-user-moderation-dropdown> ></my-user-moderation-dropdown>
<span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="pt-badge badge-danger" i18n>Banned</span> <span *ngIf="accountUser?.blocked" tabindex="0" [ngbTooltip]="accountUser.blockedReason" class="pt-badge badge-danger" i18n>Banned</span>
<my-account-block-badges [account]="account"></my-account-block-badges> <my-account-block-badges [account]="account"></my-account-block-badges>
</div> </div>
<div class="actor-handle"> <div class="actor-handle">
<span>@{{ account.nameWithHost }}</span> <span>@{{ account.nameWithHost }}</span>
<button [cdkCopyToClipboard]="account.nameWithHostForced" (click)="activateCopiedMessage()"
class="btn btn-outline-secondary btn-sm copy-button" title="Copy account handle" i18n-title <my-copy-button
> [value]="account.nameWithHostForced" i18n-notification notification="Username copied"
<my-global-icon iconName="copy"></my-global-icon> title="Copy account handle" i18n-title
</button> ></my-copy-button>
</div> </div>
<div class="actor-counters"> <div class="actor-counters">

View File

@ -28,14 +28,8 @@
} }
} }
.copy-button { my-copy-button {
@include margin-left(3px); @include margin-left(3px);
border: 0;
my-global-icon {
width: 15px;
}
} }
.account-info { .account-info {

View File

@ -13,7 +13,7 @@ import {
VideoService VideoService
} from '@app/shared/shared-main' } from '@app/shared/shared-main'
import { AccountReportComponent, BlocklistService } from '@app/shared/shared-moderation' import { AccountReportComponent, BlocklistService } from '@app/shared/shared-moderation'
import { HttpStatusCode, User, UserRight } from '@shared/models' import { HttpStatusCode, User, UserRight } from '@peertube/peertube-models'
@Component({ @Component({
templateUrl: './accounts.component.html', templateUrl: './accounts.component.html',
@ -115,10 +115,6 @@ export class AccountsComponent implements OnInit, OnDestroy {
this.redirectService.redirectToHomepage() this.redirectService.redirectToHomepage()
} }
activateCopiedMessage () {
this.notifier.success($localize`Username copied`)
}
searchChanged (search: string) { searchChanged (search: string) {
const queryParams = { search } const queryParams = { search }

View File

@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'
import { AuthService, ScreenService, ServerService } from '@app/core' import { AuthService, ScreenService, ServerService } from '@app/core'
import { ListOverflowItem } from '@app/shared/shared-main' import { ListOverflowItem } from '@app/shared/shared-main'
import { TopMenuDropdownParam } from '@app/shared/shared-main/misc/top-menu-dropdown.component' import { TopMenuDropdownParam } from '@app/shared/shared-main/misc/top-menu-dropdown.component'
import { UserRight } from '@shared/models' import { UserRight } from '@peertube/peertube-models'
@Component({ @Component({
templateUrl: './admin.component.html', templateUrl: './admin.component.html',

View File

@ -1,7 +1,7 @@
import { Routes } from '@angular/router' import { Routes } from '@angular/router'
import { EditCustomConfigComponent } from '@app/+admin/config/edit-custom-config' import { EditCustomConfigComponent } from '@app/+admin/config/edit-custom-config'
import { UserRightGuard } from '@app/core' import { UserRightGuard } from '@app/core'
import { UserRight } from '@shared/models' import { UserRight } from '@peertube/peertube-models'
export const ConfigRoutes: Routes = [ export const ConfigRoutes: Routes = [
{ {

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