Compare commits

...

545 Commits

Author SHA1 Message Date
KingLucius 469a71236b
SubDL subtitles provider (#1082) 2024-05-18 18:15:23 +02:00
CranberrySoup 4d5cd288ab
Ported more files for multiplatform (#1056) 2024-05-18 13:47:12 +02:00
KingLucius af828de8d5
feat(TV UI: Fix online subtitles dialog focus (#1085) 2024-05-18 13:41:37 +02:00
CranberrySoup ee4d1dedc5
Add basic fcast support (#1084) 2024-05-09 21:46:54 +02:00
KingLucius f1cc4db89c
Show Season number for next airing episode (#1071) 2024-05-09 17:08:18 +02:00
b4byhuey 3874cb9f9d
Update Dailymotion Extractor (#1081) 2024-05-09 17:06:33 +02:00
phisher98 0a5399d9b6
Updates and Chillx Extractor Updated (#1065) 2024-05-05 01:00:42 +02:00
KingLucius 71bd48f493
feat(ui): Hide Downloads & Settings Back button on TV (#1074) 2024-05-04 13:17:52 +02:00
KingLucius 83c473d9f8
More external Ids in Trakt meta provider (#1075) 2024-05-04 13:16:09 +02:00
RowdyRushya c28a3cb987
Extractor: new VidSrcTo extractor (#1044) 2024-05-04 13:15:34 +02:00
int3debug d3828eeafe
refact: rename logcat file (#1061)
Rename logcat file to prevent override
2024-05-02 23:59:05 +02:00
int3debug c07e6d3222
hotfix: Remove resume information (#1063) 2024-05-02 23:58:32 +02:00
KingLucius 949b5830b6
feat(ui): Fix downloads focus on TV (#1066) 2024-05-01 19:29:49 +02:00
b4byhuey ff1ffbeb83
Update Voe.kt (#1062) 2024-04-28 21:42:38 +02:00
Luna712 138e1a1f0e
Don't check year when checking duplicates if year is empty (#1060)
Some sources don't use year which makes this not match when it really should match
2024-04-27 22:40:15 +02:00
KingLucius 004c481a5e
feat(ui): Episode Air date & Upcoming countdown (#1058) 2024-04-27 18:11:22 +02:00
b4byhuey e2946cad6b
Added Vidguard Extractor (#1053) 2024-04-27 18:00:40 +02:00
int3debug e6b9d621f9
feat(ui): added option to reset sub delay (#1041) 2024-04-22 17:00:27 +02:00
KingLucius 0019f85501
Trakt meta provider for extensions (#1026) 2024-04-22 16:59:14 +02:00
IndusAryan 0744189020
feat(ui): show account name and image on main settings page (#1001) 2024-04-22 16:48:54 +02:00
Ömer Faruk Sancak 4399a612df
Update Vidmoly.kt (#1051) 2024-04-22 01:14:36 +02:00
KingLucius e01ff4d843
Fix NewPipeExtractor lib path (#1050) 2024-04-22 01:13:55 +02:00
KingLucius 6cef9f7ea2
Filtering first unwatched episode respects watched state (#1049) 2024-04-20 22:18:49 +02:00
int3debug 9a18ef6411
bugfix: fixing regex special chars break it (#1047) 2024-04-17 23:48:33 +02:00
CranberrySoup 6df3ef14f6
First steps for multiplatform API (#1003)
* First steps for multiplatform api

* Buildconfig testing

* Fix publishing and classes.jar

* Update build.gradle.kts
2024-04-16 23:07:28 +02:00
int3debug 5db541d7cc
feat(ui): added reset button to subtitle delay (#1040) 2024-04-14 02:13:12 +02:00
CranberrySoup aa8972870c
Show download size on videos (#1038) 2024-04-14 00:45:58 +02:00
Rushikesh Chavan afdc4988ac
Extractor: Update Vidplay Extractor (#1036) 2024-04-13 19:52:08 +02:00
KingLucius e6c111532d
Defaults Play button to first unwatched Episode (#1035) 2024-04-13 19:51:39 +02:00
recloudstream[bot] ffa7b0248a chore(locales): fix locale issues 2024-04-10 15:26:36 +00:00
firelight c13d290377
Merge pull request #1012 from recloudstream/weblate
Translations update from Hosted Weblate
2024-04-10 17:26:17 +02:00
Hosted Weblate 1bf7e14eab
Merge remote-tracking branch 'origin/master' 2024-04-10 17:24:19 +02:00
phisher98 145ceea50f
Created vtbe and EPlay Extractor (#1014) 2024-04-10 17:24:15 +02:00
Hosted Weblate 2fad760426
Merge remote-tracking branch 'origin/master' 2024-04-10 17:16:09 +02:00
KingLucius ff0dea3fbb
Fix focus for Tracks selection on TV (#1030) 2024-04-10 17:16:04 +02:00
Hosted Weblate 44e5b86176
Merge remote-tracking branch 'origin/master' 2024-04-10 17:14:51 +02:00
KingLucius d8f89df163
Show player controls on pressing Pad Down (#1031) 2024-04-10 17:14:47 +02:00
Hosted Weblate a74563d003
Translated using Weblate (Russian)
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Vietnamese)

Currently translated at 75.0% (3 of 4 strings)

Translated using Weblate (Vietnamese)

Currently translated at 98.7% (688 of 697 strings)

Translated using Weblate (French)

Currently translated at 96.8% (675 of 697 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Persian)

Currently translated at 34.7% (242 of 697 strings)

Translated using Weblate (Vietnamese)

Currently translated at 98.8% (689 of 697 strings)

Translated using Weblate (Russian)

Currently translated at 97.1% (677 of 697 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Malayalam)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Malayalam)

Currently translated at 48.4% (338 of 697 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.8% (696 of 697 strings)

Translated using Weblate (Maltese)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Maltese)

Currently translated at 32.1% (224 of 697 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (697 of 697 strings)

Added translation using Weblate (Maltese)

Translated using Weblate (Spanish)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.1% (684 of 697 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (697 of 697 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Spanish)

Currently translated at 99.4% (690 of 694 strings)

Translated using Weblate (Odia)

Currently translated at 37.5% (258 of 688 strings)

Co-authored-by: Andre Costa <andrecaeu@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Argo Carpathians <chrisarabagas@gmail.com>
Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Colgrave <hanqixu.blogs@simplelogin.co>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Fqwe1 <Fqwe1@users.noreply.hosted.weblate.org>
Co-authored-by: Gnkalk <github.fngyb@slmail.me>
Co-authored-by: Herderson Riker <herdersonriker@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Joshua Joseph <joshuasaju2@gmail.com>
Co-authored-by: Long Kim <kimlong01102000@icloud.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Matthaiks <kitynska@gmail.com>
Co-authored-by: Michael John Scerri <michaeljscerri@gmail.com>
Co-authored-by: Mika <akimivanov43@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Thanh <pancakes21f@gmail.com>
Co-authored-by: aleksej0R <omolice@hotmail.fr>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Co-authored-by: maxim <maximtested@gmail.com>
Co-authored-by: samwiaba <sambastianc@gmail.com>
Co-authored-by: Ömer Faruk Sancak <keyiflerolsun@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/mt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/vi/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2024-04-08 04:02:02 +02:00
firelight 0a24661e4c
fix latest commit 2024-03-25 01:48:23 +01:00
firelight ed2bdf44fb
New TvTypes + General fixes 2024-03-25 01:38:39 +01:00
IndusAryan 51d91bf9a7
feat(ui): add ignore battery optimisation dialog for uniterrupted downloads and notifications (#915) 2024-03-25 01:18:26 +01:00
firelight fb89fd60b8
Merge pull request #996 from KingLucius/playFirstUnwatched
Set play button to first unwatched Episode on TV
2024-03-25 01:05:41 +01:00
recloudstream[bot] 7db7742c73 chore(locales): fix locale issues 2024-03-25 00:04:49 +00:00
firelight b246d80861
Merge pull request #890 from recloudstream/weblate
Translations update from Hosted Weblate
2024-03-25 01:04:36 +01:00
Hosted Weblate d321aba3a7
Merge remote-tracking branch 'origin/master' 2024-03-25 01:03:08 +01:00
IndusAryan 22937424fa
feat(ui): authenticate first when enabling security settings (#991) 2024-03-25 01:03:04 +01:00
Hosted Weblate 7f0034e872
Merge remote-tracking branch 'origin/master' 2024-03-25 00:59:59 +01:00
IndusAryan 35e38a53ad
refactor: format build date and time and make it copyable (#1002) 2024-03-25 00:59:55 +01:00
Hosted Weblate 6d8a31809d
Merge remote-tracking branch 'origin/master' 2024-03-25 00:55:53 +01:00
KingLucius 650c7583af
Fix Alert Dialog width on TV (#1010)
* Fix Alert Dialog width on TV

* Fix width for AlertDialogCustom on TV
2024-03-25 00:55:37 +01:00
Hosted Weblate 34af3a4b2f
Merge remote-tracking branch 'origin/master' 2024-03-25 00:47:29 +01:00
int3debug 9ef1f1cc41
fix: extension activity interruption (#1005)
fixed interruption with only local plugins

Co-authored-by: int3debug <gh.ditch236@passinbox.com>
2024-03-25 00:47:26 +01:00
Hosted Weblate 6ede44d85f
Merge remote-tracking branch 'origin/master' 2024-03-25 00:42:23 +01:00
KingLucius 2f03ca7de9
Extenstions' Github & Rate buttons are now focusable on TV (#1008)
- Disables useless focus for (Description, Author .. etc.) buttons one the left.
- Make GitHub & Rate focusable on TV.
2024-03-25 00:42:18 +01:00
Hosted Weblate 7ce2dfc4aa
Merge remote-tracking branch 'origin/master' 2024-03-25 00:41:08 +01:00
int3debug 16510923d2
fix: No access rights after restore from backup (#1009)
Co-authored-by: int3debug <gh.ditch236@passinbox.com>
2024-03-25 00:41:04 +01:00
Hosted Weblate a9c2c0644a
Translated using Weblate (Indonesian)
Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.4% (677 of 688 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (French)

Currently translated at 98.1% (675 of 688 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.8% (687 of 688 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Croatian)

Currently translated at 99.2% (683 of 688 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (German)

Currently translated at 99.7% (686 of 688 strings)

Translated using Weblate (English)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (688 of 688 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (688 of 688 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Afrikaans)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Afrikaans)

Currently translated at 29.7% (205 of 688 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.7% (686 of 688 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Hindi)

Currently translated at 40.9% (282 of 688 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (688 of 688 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (688 of 688 strings)

Merge remote-tracking branch 'origin/master'

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Levantine))

Currently translated at 99.7% (684 of 686 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.7% (684 of 686 strings)

Translated using Weblate (German)

Currently translated at 99.8% (685 of 686 strings)

Translated using Weblate (Malayalam)

Currently translated at 44.0% (302 of 686 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (686 of 686 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (686 of 686 strings)

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Levantine))

Currently translated at 98.6% (678 of 687 strings)

Translated using Weblate (German)

Currently translated at 98.9% (680 of 687 strings)

Translated using Weblate (German)

Currently translated at 98.9% (680 of 687 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Swedish)

Currently translated at 99.8% (686 of 687 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.6% (678 of 687 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Swedish)

Currently translated at 99.8% (683 of 684 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (684 of 684 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Persian)

Currently translated at 33.7% (228 of 675 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Hungarian)

Currently translated at 95.1% (642 of 675 strings)

Translated using Weblate (Romanian)

Currently translated at 94.2% (636 of 675 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Hungarian)

Currently translated at 86.3% (583 of 675 strings)

Translated using Weblate (Hindi)

Currently translated at 41.6% (281 of 675 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Russian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (German)

Currently translated at 98.0% (662 of 675 strings)

Translated using Weblate (Portuguese)

Currently translated at 96.4% (651 of 675 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (French)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 97.3% (657 of 675 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (675 of 675 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Italian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 99.7% (672 of 674 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Vietnamese)

Currently translated at 98.6% (665 of 674 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Bulgarian)

Currently translated at 98.9% (667 of 674 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Nepali)

Currently translated at 26.8% (181 of 674 strings)

Translated using Weblate (Afrikaans)

Currently translated at 29.9% (202 of 674 strings)

Translated using Weblate (Amharic)

Currently translated at 29.6% (200 of 674 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 42.8% (289 of 674 strings)

Translated using Weblate (Kannada)

Currently translated at 33.8% (228 of 674 strings)

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Macedonian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Dutch)

Currently translated at 99.5% (666 of 669 strings)

Translated using Weblate (Macedonian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.2% (664 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.2% (664 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.0% (649 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.0% (649 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 95.9% (642 of 669 strings)

Translated using Weblate (French)

Currently translated at 99.4% (665 of 669 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Esperanto)

Currently translated at 33.7% (226 of 669 strings)

Translated using Weblate (Urdu)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Bulgarian)

Currently translated at 99.8% (668 of 669 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (French)

Currently translated at 99.4% (665 of 669 strings)

Translated using Weblate (Portuguese)

Currently translated at 95.9% (642 of 669 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (669 of 669 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Japanese)

Currently translated at 50.2% (336 of 669 strings)

Translated using Weblate (Hungarian)

Currently translated at 82.8% (554 of 669 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (669 of 669 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Russian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (669 of 669 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Croatian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Russian)

Currently translated at 94.7% (634 of 669 strings)

Translated using Weblate (Croatian)

Currently translated at 75.0% (3 of 4 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (669 of 669 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (German)

Currently translated at 99.1% (663 of 669 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.2% (603 of 668 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Japanese)

Currently translated at 49.8% (333 of 668 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 96.5% (645 of 668 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Swedish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Japanese)

Currently translated at 47.3% (316 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 99.4% (664 of 668 strings)

Translated using Weblate (Nepali)

Currently translated at 26.9% (180 of 668 strings)

Translated using Weblate (German)

Currently translated at 99.1% (662 of 668 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Odia)

Currently translated at 38.3% (256 of 668 strings)

Translated using Weblate (Croatian)

Currently translated at 99.7% (666 of 668 strings)

Translated using Weblate (Nepali)

Currently translated at 16.9% (113 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Polish)

Currently translated at 99.7% (666 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 45.2% (302 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 36.8% (246 of 668 strings)

Translated using Weblate (Tagalog)

Currently translated at 51.9% (347 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 78.8% (527 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 39.0% (261 of 668 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Polish)

Currently translated at 98.6% (659 of 668 strings)

Co-authored-by: Aayush Shah <shahaayush999@gmail.com>
Co-authored-by: Ahmed Abd El-Fattah <a.aelfattah5@gmail.com>
Co-authored-by: Alexander Svärd <genc.demiri@hotmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Amir <amearb@duck.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Andre Costa <andrecaeu@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Apostol Penkov <apostol.penkov@gmail.com>
Co-authored-by: AppsTool <appstool03@gmail.com>
Co-authored-by: Argo Carpathians <chrisarabagas@gmail.com>
Co-authored-by: Bálint László <blaszlobors@gmail.com>
Co-authored-by: CPavRou <mag@cleparo.fr>
Co-authored-by: CakesTwix <cakestwix1@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Colgrave <hanqixu.blogs@simplelogin.co>
Co-authored-by: Dan <jonweblin2205@protonmail.com>
Co-authored-by: DarkOrbFX <darkorbfx@gmail.com>
Co-authored-by: Davi Silveira <davilego10@gmail.com>
Co-authored-by: Davide Marcoli <davide.marcoli13@gmail.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Fqwe1 <Fqwe1@users.noreply.hosted.weblate.org>
Co-authored-by: Friso de Boer <collorfrisie@hotmail.com>
Co-authored-by: Gnkalk <github.fngyb@slmail.me>
Co-authored-by: H Tamás <hovanszki@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Hubert Naciasta <hubert.naciasta@skiff.com>
Co-authored-by: IamNotNickerson <IamNickerson@users.noreply.hosted.weblate.org>
Co-authored-by: Jean-Michel <arsene_lupin_57@hotmail.fr>
Co-authored-by: Joana Trashlieva <j.trashlieva@gmail.com>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Julia Sugawara <jm.sugawara@gmail.com>
Co-authored-by: Just Rocket (just) <phatal1988@gmail.com>
Co-authored-by: Kjev <77635620+Kjev666@users.noreply.github.com>
Co-authored-by: Levent SD <leventsd@gmail.com>
Co-authored-by: Luna712 <142361265+Luna712@users.noreply.github.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Matthaiks <kitynska@gmail.com>
Co-authored-by: Mc wolmarans <marthinuswolmarans61@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Naga <yz2000.pro@gmail.com>
Co-authored-by: NamelessGO <66227691+NameLessGO@users.noreply.github.com>
Co-authored-by: Only1337 <ymurathanusta@gmail.com>
Co-authored-by: Ovi329 <avijitb129@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sanjeev Dhawan <smstranscom@gmail.com>
Co-authored-by: Semih <semihbrn10@gmail.com>
Co-authored-by: Slawa <slawa@slawagurevich.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: Sufyan Zahoor Jutt <sufyanpahore@gmail.com>
Co-authored-by: T1z3n <info@njbraun.de>
Co-authored-by: TecnoLAZ <luispaulodias89@gmail.com>
Co-authored-by: Yosra Boussaid <yosra.boussaid@users.noreply.hosted.weblate.org>
Co-authored-by: Zhenye Dong <dongzhenye@gmail.com>
Co-authored-by: arcopnt <arcopnt@posteo.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: delvani <inavleb@users.noreply.hosted.weblate.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: konatu saino <shironyann.tdbr@gmail.com>
Co-authored-by: lucasmz <github@lucasmz.dev>
Co-authored-by: maxim <maximtested@gmail.com>
Co-authored-by: oops-wtf <cert.potatoes@gmail.com>
Co-authored-by: simmon <simmon@nplob.com>
Co-authored-by: stojkovskistefan <stefanstojkovski@gmail.com>
Co-authored-by: tuan041 <tuananh163025ttt@gmail.com>
Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Co-authored-by: Ícaro Rodrigo Ferreira Da Fonseca Bezerra <icaro.bezerra@sptech.school>
Co-authored-by: Ömer Faruk Sancak <keyiflerolsun@gmail.com>
Co-authored-by: Сергій <sergiy.goncharuk.1@gmail.com>
Co-authored-by: सौम्य भाटी <saumyabhati2006@gmail.com>
Co-authored-by: 电棍老板 <qwertyuiop9296@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/af/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/am/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/eo/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ne/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ur/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/af/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/ko/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/zh_Hans/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2024-03-24 20:01:55 +01:00
firelight 4468ce3d80
Revert "make cloudstream very superfast boi, fast app startup and navigation …" (#1007)
This reverts commit faeb71da2c.
2024-03-22 23:06:05 +01:00
IndusAryan faeb71da2c
make cloudstream very superfast boi, fast app startup and navigation (#965) 2024-03-22 22:56:05 +01:00
int3debug 86bc0b8345
fixed first setup extension activity interruption (#1000)
Co-authored-by: int3debug <gh.ditch236@passinbox.com>
2024-03-22 22:31:01 +01:00
int3debug 1ff0b5dccd
add build-date to main_settings (#995) 2024-03-20 08:33:50 +01:00
KingLucius a2e63174be Set play button to first unwatched episode on TV 2024-03-19 17:47:36 +02:00
Osten eb60be54ed fixed crash + fixed lib + fixed preview 2024-03-18 15:54:54 +01:00
Osten 8d5b73495d Added BaseAdapter to store internal state 2024-03-18 03:58:30 +01:00
KingLucius a3bb853691
Extension's Settings Focus on TV (#990) 2024-03-17 17:07:18 +01:00
Osten 375b3ec46e
Update HomeParentItemAdapter.kt
Should fix last item problem
2024-03-17 16:42:31 +01:00
Osten ad67b9ddab + Fixed ephemeral scroll
+ Fixed Unable to remove Subs
+ Fixed download 1 frame visual glitch
+ Maybe fixed worker
+ Updated layout API
+ Bump
2024-03-17 03:37:09 +01:00
KingLucius 638cc4fee9
New TV UI bug fixes (#983) 2024-03-16 03:50:49 +01:00
IndusAryan 4817b29b9c
refactor: toast view to use data binding (#919) 2024-03-14 00:12:13 +01:00
IndusAryan 040ac77b1a
refactor: add clipboard helper and improve repo url copy (#946) 2024-03-14 00:04:58 +01:00
firelight 527046766a
Fixed OOM when using restore data 2024-03-13 23:36:23 +01:00
Luna712 adc653943b
Improve synopsis/description display on phone and emulator (#967) 2024-03-13 18:29:12 +01:00
IndusAryan 81df68e137
fix(hotfix): bottom sheet appearing when turning biometrics off and remove toast. (#971)
* fix biometric regressions

* use nullable context

* aha!
2024-03-10 23:15:23 +01:00
Luna712 a01bb9e55b
Fix nonTransferableKeys in BackupUtils (#979)
* Fix nonTransferableKeys in BackupUtils

* Whoops...

* really...
2024-03-10 23:12:51 +01:00
Luna712 807bd85fa9
Move biometric_key to keys section in strings (#978) 2024-03-10 23:11:02 +01:00
KingLucius 510d11f705
New TV UI (#950) 2024-03-09 15:24:38 +01:00
firelight bd69054f5d
Updated lib icon 2024-03-08 03:16:36 +01:00
firelight 694e7abbdf
Fixes #816 2024-03-08 03:00:00 +01:00
firelight e3f9f255c7
Revert "feat: make cloudstream compilation and builds fast! using gradle conf…" (#968)
This reverts commit 21b341e12f.
2024-03-08 02:07:35 +01:00
IndusAryan 21b341e12f
feat: make cloudstream compilation and builds fast! using gradle configuration cache (#959) 2024-03-08 01:56:31 +01:00
IndusAryan e3999d6e9a
feat(security): add biometric fingerprint sensor / face unlock authentication (#826) 2024-03-08 01:45:20 +01:00
Mater Yoda f0f4ec87bc
Added lavender color (#949) 2024-03-08 01:20:49 +01:00
self-similarity 809a38507b
Update SimklApi.kt (#961) 2024-03-02 23:45:18 +01:00
KingLucius 1a380a3239
TV show airing status for phone (#953)
* TV show airing status for phone

* Bump Nicehttp & remove toImmutableList
2024-02-29 17:07:45 +01:00
Sofie 93d81ea038
WebViewResolver: added timeout (#941) 2024-02-19 21:18:36 +01:00
Sofie e007714701
fix Rabbitstream (#936)
* fix Rabbitstream

* .
2024-02-19 21:06:55 +01:00
KingLucius 805f80b2ac
Long press Repo to copy URL (#934) 2024-02-19 16:46:02 +01:00
KingLucius b5fb0997c4
[TV] Limit Homepage Header Description to 3 lines & 6 Tags (#938) 2024-02-19 16:44:50 +01:00
KingLucius ca918b1581
[TV] More space around result description (#939) 2024-02-19 16:43:41 +01:00
IndusAryan 09779b4ee0
chore: add tooltips on results toolbar and rename speed mode (#925)
* add tooltips on results toolbar and better summaries, rename speed mode

* remove redundant space
2024-02-15 21:45:34 +01:00
Sofie 012d38398e
fix Acefile & Gofile (#926) 2024-02-15 21:42:47 +01:00
Ömer Faruk Sancak d1db4c3370
Extractor: Added PlayRu (#930) 2024-02-15 21:42:11 +01:00
Sarlay 8d318ca84a
Fixed Chillx subtitles (#931)
* Fixed subtitles tracks for Chillx.kt

* Update Chillx.kt
2024-02-15 21:41:34 +01:00
KingLucius eea6e13346
Make Rating non-focusable (Old API) (#935) 2024-02-15 21:40:44 +01:00
CranberrySoup 2b7d102716
Add SubScene (#923)
* Lower targetSdk to get all installed packages

* Update sdk version

* Let's not be too radical

* Many fixes

* Revert targetSdk

* Make account homepage persistent

* Add SubScene and change subtitle API

Co-authored-by: Aymanbest <51868001+aymanbest@users.noreply.github.com>

* Fix file deletion

---------

Co-authored-by: Aymanbest <51868001+aymanbest@users.noreply.github.com>
2024-02-06 23:27:35 +01:00
Osten 9ea7674a0f
Update MainAPI.kt 2024-02-02 22:18:54 +01:00
IndusAryan 3dcf7076d0
feat(ui): tap video duration to toggle remaining time counter (#878) 2024-01-21 20:11:51 +01:00
Sofie 8b14fcb881
added Mediafire (#906) 2024-01-21 15:35:33 +01:00
IndusAryan 01f21e0fe8
refactor: move buildconfig, bump ksp & better trailer scraping (#834) 2024-01-19 21:09:07 +01:00
coxju bdef6524e7
feat : run custom js in webviewresolver (#888)
Co-authored-by: coxju <coxju>
2024-01-19 20:38:37 +01:00
Cloudburst f40a8d9418
make *rotate_video_key untransatable (#896) 2024-01-19 20:12:52 +01:00
IndusAryan 03fcb106ac
new simple messages when updating app i.e, refined changelogs (#900) 2024-01-19 20:12:33 +01:00
coxju 636e157c63
fix: trailers not playing (#898)
Co-authored-by: coxju <coxju>
2024-01-19 12:03:20 +01:00
CranberrySoup 5af1b80cb7
Fix crash on plugin reload (#895)
* Update Event.kt

* Update Event.kt
2024-01-18 22:57:54 +01:00
coxju 5dfc08aabb
feat: added emturbovid extractor (#893)
Co-authored-by: coxju <coxju>
2024-01-17 23:28:17 +01:00
coxju 1676094488
feat (loadExtractor) : match mirror domains of extractor link (#877)
Co-authored-by: coxju <coxju>
2024-01-17 22:32:22 +01:00
Sir Aguacata 19145c6cc4
Screw it, Self host keys (#892) 2024-01-17 22:30:20 +01:00
coxju ebb72d6a0c
feat : invalidate link cache after 20 mins (#875)
- additionaly clear cache if there is player errors or no links found

Co-authored-by: coxju <coxju>
2024-01-17 22:29:44 +01:00
Sir Aguacata 399b28c75b
Rest in piece old key repo (#891) 2024-01-17 00:35:23 +01:00
IndusAryan 601483e103
feat: limit genre tags on home to 2 lines and on result page, 10 tags max (#885) 2024-01-16 18:41:43 +01:00
recloudstream[bot] 9733d0b316 chore(locales): fix locale issues 2024-01-16 17:40:50 +00:00
Weblate (bot) 0cf199248a
Translated using Weblate (Croatian) (#856)
Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Russian)

Currently translated at 94.7% (634 of 669 strings)

Translated using Weblate (Croatian)

Currently translated at 75.0% (3 of 4 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (669 of 669 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (German)

Currently translated at 99.1% (663 of 669 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.2% (603 of 668 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Japanese)

Currently translated at 49.8% (333 of 668 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 96.5% (645 of 668 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Swedish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Japanese)

Currently translated at 47.3% (316 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 99.4% (664 of 668 strings)

Translated using Weblate (Nepali)

Currently translated at 26.9% (180 of 668 strings)

Translated using Weblate (German)

Currently translated at 99.1% (662 of 668 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Odia)

Currently translated at 38.3% (256 of 668 strings)

Translated using Weblate (Croatian)

Currently translated at 99.7% (666 of 668 strings)

Translated using Weblate (Nepali)

Currently translated at 16.9% (113 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Polish)

Currently translated at 99.7% (666 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 45.2% (302 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 36.8% (246 of 668 strings)

Translated using Weblate (Tagalog)

Currently translated at 51.9% (347 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 78.8% (527 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 39.0% (261 of 668 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Polish)

Currently translated at 98.6% (659 of 668 strings)























Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ne/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/sv/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane

Co-authored-by: Aayush Shah <shahaayush999@gmail.com>
Co-authored-by: Alexander Svärd <genc.demiri@hotmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Amir <amearb@duck.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hubert Naciasta <hubert.naciasta@skiff.com>
Co-authored-by: IamNotNickerson <IamNickerson@users.noreply.hosted.weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Ovi329 <avijitb129@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Slawa <slawa@slawagurevich.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Co-authored-by: Ömer Faruk Sancak <keyiflerolsun@gmail.com>
Co-authored-by: Сергій <sergiy.goncharuk.1@gmail.com>
2024-01-16 18:40:37 +01:00
Sofie 2624947b5b
fix keys (#887)
Co-authored-by: ghost <ghost@gmail.com>
2024-01-16 18:37:31 +01:00
coxju 31c783d0b4
feat: added extractor vidhide and streamwish (#889)
Co-authored-by: coxju <coxju>
2024-01-16 18:36:02 +01:00
firelight 9f1b172f34
fix plugin downloads trash can 2024-01-14 01:06:06 +01:00
IndusAryan 93dce8682e
fix system bars not appearing properly (#879) 2024-01-13 22:45:30 +01:00
IndusAryan 723c653b07
feat(ui): long press title to copy (#872)
* new feature: hold to copy movie title

* remove title copy hint
2024-01-12 16:48:43 +01:00
coxju 0c73f5e59a
fix: library not loading in TV (#871) 2024-01-11 17:08:37 +01:00
coxju 0eb152c5db
fix: search only if selection changed (#868) 2024-01-11 15:54:28 +01:00
IndusAryan 8c5ab86714
hotfix window compat bug (#870) 2024-01-11 15:53:31 +01:00
Ömer Faruk Sancak 85a769a898
Extractor: ContentX add external subtitle (#869) 2024-01-11 15:52:34 +01:00
Sir Aguacata 96aa56209b
Revert the repo change to get keys (#867) 2024-01-11 00:47:40 +01:00
coxju d71d3890b5
feat: show random button on library (#855) 2024-01-10 22:28:06 +01:00
IndusAryan 19b1a40cf8
use window insets compat controller (#847) 2024-01-10 22:20:43 +01:00
Yutatsu e5f483b0b2
Fix vidplay extractor (#866) 2024-01-10 22:06:45 +01:00
coxju 6f1e0bef80
feat: show the episodic range with current selection checked (#851) 2024-01-10 22:05:56 +01:00
LagradOst 5e6272be3f fix 2024-01-10 19:10:34 +01:00
coxju 97ec98b9e2
feat : show favorite button in bottom dialog (#858)
Co-authored-by: coxju <coxju>
2024-01-10 18:55:10 +01:00
coxju 42fd0b5c76
new streamtape extractor (#857) 2024-01-08 23:46:19 +01:00
Ömer Faruk Sancak 42774f6183
Extractor: ContentX expanded and fix (#859)
* Extractor: ContentX expanded and fix
2024-01-08 23:45:53 +01:00
Sofie f687508521
Extractors: fix acefile, pixeldrain & vidplay tracks (#854)
Co-authored-by: ghost <ghost@gmail.com>
2024-01-05 17:08:48 +01:00
recloudstream[bot] dbba6d7f27 chore(locales): fix locale issues 2024-01-05 16:08:37 +00:00
Hosted Weblate f4da170a57 Translated using Weblate (Polish)
Currently translated at 99.7% (666 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 45.2% (302 of 668 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 27.6% (185 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 36.8% (246 of 668 strings)

Translated using Weblate (Tagalog)

Currently translated at 51.9% (347 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 78.8% (527 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 39.0% (261 of 668 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Polish)

Currently translated at 98.6% (659 of 668 strings)

Co-authored-by: Amir <amearb@duck.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Hubert Naciasta <hubert.naciasta@skiff.com>
Co-authored-by: IamNotNickerson <IamNickerson@users.noreply.hosted.weblate.org>
Co-authored-by: Ovi329 <avijitb129@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/apc/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2024-01-05 17:08:20 +01:00
Cloudburst 2a1876f54c
fix build_to_archive.yml 2024-01-03 10:28:39 +01:00
wrongwrong f1d0a8e955
Fixed to not use API that will be discontinued in the future (#843) 2024-01-03 10:24:42 +01:00
IndusAryan 1c6be2d5cb
refactor(bump): upgrade workflow versions to use node16 (#793) 2024-01-03 10:24:28 +01:00
Horis fc802cdcdd
add extractors (#849) 2024-01-03 10:24:12 +01:00
Ömer Faruk Sancak 2cfdab5498
Extractor: added some extractors (#833)
* Extractor: added some extractors

* Extractor: fix same import

* Extractor: PeaceMakerst fix

* Extractor: source fix
2023-12-31 21:31:05 +01:00
recloudstream[bot] 4c2ee28d5a chore(locales): fix locale issues 2023-12-28 13:17:57 +00:00
firelight 657f2fbcb2
Merge pull request #824 from recloudstream/weblate
Translations update from Hosted Weblate
2023-12-28 14:17:41 +01:00
Hosted Weblate b5ac668493
Added translation using Weblate (Nepali)
Translated using Weblate (Ukrainian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 75.0% (3 of 4 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Hindi)

Currently translated at 41.9% (280 of 668 strings)

Translated using Weblate (French)

Currently translated at 98.5% (658 of 668 strings)

Translated using Weblate (Italian)

Currently translated at 99.2% (663 of 668 strings)

Translated using Weblate (Hindi)

Currently translated at 38.1% (255 of 668 strings)

Translated using Weblate (Burmese)

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Galician)

Currently translated at 38.9% (260 of 668 strings)

Translated using Weblate (Odia)

Currently translated at 38.1% (255 of 668 strings)

Translated using Weblate (Latvian)

Currently translated at 92.3% (617 of 668 strings)

Translated using Weblate (Somali)

Currently translated at 85.1% (569 of 668 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 43.1% (288 of 668 strings)

Translated using Weblate (Persian)

Currently translated at 22.6% (151 of 668 strings)

Translated using Weblate (Tamil)

Currently translated at 21.1% (141 of 668 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 94.0% (628 of 668 strings)

Translated using Weblate (Tagalog)

Currently translated at 51.3% (343 of 668 strings)

Translated using Weblate (Swedish)

Currently translated at 78.7% (526 of 668 strings)

Translated using Weblate (Romanian)

Currently translated at 90.8% (607 of 668 strings)

Translated using Weblate (Polish)

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 89.5% (598 of 668 strings)

Translated using Weblate (French)

Currently translated at 98.5% (658 of 668 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.5% (665 of 668 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Lithuanian)

Currently translated at 48.5% (324 of 668 strings)

Translated using Weblate (Amharic)

Currently translated at 29.6% (198 of 668 strings)

Translated using Weblate (Tigrinya)

Currently translated at 15.1% (101 of 668 strings)

Translated using Weblate (Korean)

Currently translated at 92.3% (617 of 668 strings)

Translated using Weblate (Malay)

Currently translated at 22.9% (153 of 668 strings)

Translated using Weblate (Japanese)

Currently translated at 46.5% (311 of 668 strings)

Translated using Weblate (qt (generated) (qt))

Currently translated at 50.5% (338 of 668 strings)

Translated using Weblate (Portuguese)

Currently translated at 94.1% (629 of 668 strings)

Translated using Weblate (Hungarian)

Currently translated at 82.0% (548 of 668 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Russian)

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Kannada)

Currently translated at 33.9% (227 of 668 strings)

Translated using Weblate (Urdu)

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Hebrew)

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Bengali)

Currently translated at 36.3% (243 of 668 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Malayalam)

Currently translated at 38.7% (259 of 668 strings)

Translated using Weblate (Macedonian)

Currently translated at 92.3% (617 of 668 strings)

Translated using Weblate (Greek)

Currently translated at 94.0% (628 of 668 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (668 of 668 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 94.9% (634 of 668 strings)

Translated using Weblate (Bulgarian)

Currently translated at 93.5% (625 of 668 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.8% (660 of 668 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 91.6% (612 of 668 strings)

Translated using Weblate (Macedonian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 92.1% (610 of 662 strings)

Translated using Weblate (Macedonian)

Currently translated at 92.2% (611 of 662 strings)

Translated using Weblate (German)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (German)

Currently translated at 99.6% (660 of 662 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (English)

Currently translated at 75.0% (3 of 4 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 99.8% (660 of 661 strings)

Translated using Weblate (Italian)

Currently translated at 98.7% (653 of 661 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (German)

Currently translated at 99.6% (659 of 661 strings)

Translated using Weblate (French)

Currently translated at 98.1% (649 of 661 strings)

Co-authored-by: Aayush Shah <shahaayush999@gmail.com>
Co-authored-by: Azgar <azgar4485@gmail.com>
Co-authored-by: Dan <jonweblin2205@protonmail.com>
Co-authored-by: Emanuele Frasca <noostale@live.it>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Filip Drogrishki <alekfilip425@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Giuseppe Terrana <terranagiuseppe03@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Lacey Anaya <yecakeh263@anawalls.com>
Co-authored-by: Luna712 <142361265+Luna712@users.noreply.github.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Samuele Righi <blackdestinyx145@gmail.com>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: almost gamer <almost.gamer01+language@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Ömer Faruk Sancak <keyiflerolsun@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/am/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/gl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/he/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ko/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/lt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/lv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ms/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/my/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/qt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/so/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ta/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ti/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ur/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/uk/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2023-12-28 01:52:53 +01:00
Sofie 9d3b2ba3d2
vidplay/fallback : change to previous key (#836)
* change key

* fix rabbitstream's key
2023-12-23 23:55:02 +01:00
Osten 5f51a8f7bc
Update WatchType.kt 2023-12-21 00:10:20 +01:00
LagradOst e886fde8b8 lib longhold 2023-12-21 00:07:39 +01:00
Sofie 1356a954f3
Vidplay: change for more accurate key (#831) 2023-12-20 01:18:32 +01:00
firelight 3d90af29eb
bookmark button on preview 2023-12-19 15:59:24 +01:00
recloudstream[bot] 2a4ce89452 chore(locales): fix locale issues 2023-12-19 14:22:10 +00:00
firelight 0543f1ffae
Merge pull request #799 from recloudstream/weblate
Translations update from Hosted Weblate
2023-12-19 14:21:55 +00:00
coxju a5f7920bca
feat (player): optional rotate button in player and setting to enable auto rotate based on video orientation (#813)
Co-authored-by: coxju <coxju>
2023-12-19 15:20:58 +01:00
Hosted Weblate e8fe2944bb
Translated using Weblate (German)
Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (German)

Currently translated at 99.6% (660 of 662 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (English)

Currently translated at 75.0% (3 of 4 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Italian)

Currently translated at 99.8% (660 of 661 strings)

Translated using Weblate (Italian)

Currently translated at 98.7% (653 of 661 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (German)

Currently translated at 99.6% (659 of 661 strings)

Translated using Weblate (French)

Currently translated at 98.1% (649 of 661 strings)

Co-authored-by: Azgar <azgar4485@gmail.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Giuseppe Terrana <terranagiuseppe03@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Lacey Anaya <yecakeh263@anawalls.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Samuele Righi <blackdestinyx145@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/en/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2023-12-19 09:10:19 +00:00
Luna712 db91552f39
PluginManager: uncomment setReadOnly for Android 14 (#823) 2023-12-18 18:49:08 +01:00
Luna712 484c21cc1c
CS3IPlayer: stop player when releasing (#822) 2023-12-17 20:04:20 +01:00
Sofie ff9144ef54
fix exception (#819) 2023-12-16 20:13:19 +01:00
Luna712 10a477c2bd
Show toast when reloading links (#818)
I'm not really sure if this should be done or not. But I like to know if I actually press the button or miss click as I often have to press it twice for it to do anything, which might just be another issue though.
2023-12-16 18:42:51 +01:00
firelight 6d51c59b18
fix visibility 2023-12-15 15:24:08 +00:00
Sofie f98ce0558d
add prevent option in CloudflareKiller (#808)
* add prevent option in CloudflareKiller
2023-12-15 15:34:58 +01:00
firelight f5e6d98cb0
refactor (library search): sort and query current page only and delay search when typing (#806)
* refactor (library): delay search when typing

* fix comment

* review fixes

---------

Co-authored-by: Funny-Pen-7005 <Funny-Pen-7005>
2023-12-15 15:32:21 +01:00
coxju 91dc83e6a3
refactor (search filter) : syncing main tytype chips and bottom dialog tytype chips (#811) 2023-12-15 15:20:37 +01:00
IndusAryan fe30a85a1c
refactor: general and ui settings and added explicit unstable api opt ins (#787) 2023-12-13 22:18:12 +01:00
yueehaoo 6e5a52e440
Fixing Source List Displaying Empty Items (#810)
* Fixing source list displaying empty items
2023-12-13 20:49:42 +01:00
coxju 410cedc128
refactor (home) : show account icon when no provider selected (#812)
Co-authored-by: Funny-Pen-7005 <Funny-Pen-7005>
2023-12-13 20:23:30 +01:00
Luna712 3c152e04d1
Support showing content ratings for TmdbProvider (#705)
* Support showing content ratings for TmdbProvider
2023-12-09 18:54:29 +01:00
Osten d0aed5e51a
bump 2023-12-09 18:54:09 +01:00
Funny-Pen-7005 530619c8d0
fixes (library): reverted and updated currentPage logic (#802)
Co-authored-by: Funny-Pen-7005 <Funny-Pen-7005>
2023-12-09 16:38:39 +01:00
firelight 3ef8f3030c
fix from pr (#801) 2023-12-09 15:04:26 +01:00
Funny-Pen-7005 2d87983eca
fix (library tab): save and restore tab selection (#798)
Co-authored-by: Funny-Pen-7005 <Funny-Pen-7005>
2023-12-09 14:55:13 +01:00
Sofie 6f3a8c1cd2
extractor: added vidplay and fix few extractors (#795)
* extractor: added Vidplay

* fix id

* fix Chillx

* fix Linkbox

* update m3u8helper in chillx

* fix Dailymotion

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-12-08 17:28:16 +01:00
recloudstream[bot] dfd6ce7651 chore(locales): fix locale issues 2023-12-07 20:54:23 +00:00
firelight 88ad64b3b0
Merge pull request #790 from recloudstream/weblate
Translations update from Hosted Weblate
2023-12-07 20:54:07 +00:00
Hosted Weblate cebdbd2199
Merge remote-tracking branch 'origin/master' 2023-12-07 20:51:46 +00:00
IndusAryan 25b042fb83
refactor(bump): update glide module and fix regressions (#789)
* upgrade glide module and glide ksp

* fix glide breaking changes and regressions
2023-12-07 21:51:42 +01:00
Hosted Weblate fac0ef4c25
Merge remote-tracking branch 'origin/master' 2023-12-07 20:44:17 +00:00
IndusAryan f7bc83024a
upstream kotlin symbol processing (#788) 2023-12-07 21:44:12 +01:00
Hosted Weblate 5b170c0573
Merge remote-tracking branch 'origin/master' 2023-12-07 21:43:56 +01:00
firelight 38cc121755
Update build.gradle.kts (#797) 2023-12-07 21:43:52 +01:00
Hosted Weblate 951b2110ad
Merge remote-tracking branch 'origin/master' 2023-12-07 21:42:39 +01:00
IndusAryan d4aefc4e64
bump guava, json(tests), kgp, desugaring (#781)
* bump guava(for ksp)

* Update build.gradle.kts

* .

* Update kotlin gradle plugin
2023-12-07 21:42:32 +01:00
Hosted Weblate c324eaf543
Translated using Weblate (Hungarian)
Currently translated at 81.5% (539 of 661 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (661 of 661 strings)

Co-authored-by: Gyuri Bajzik <bajzikgy@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: Ömer Faruk Sancak <keyiflerolsun@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/tr/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2023-12-02 08:04:30 +01:00
recloudstream[bot] 962ff1c058 chore(locales): fix locale issues 2023-11-27 21:48:42 +00:00
firelight 7165b57268
Merge pull request #754 from recloudstream/weblate
Translations update from Hosted Weblate
2023-11-27 21:48:24 +00:00
Hosted Weblate e80dc63381
Translated using Weblate (Russian)
Currently translated at 94.7% (626 of 661 strings)

Translated using Weblate (Russian)

Currently translated at 94.5% (625 of 661 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (661 of 661 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Portuguese)

Currently translated at 94.8% (627 of 661 strings)

Translated using Weblate (Japanese)

Currently translated at 46.4% (307 of 661 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Bengali)

Currently translated at 36.3% (240 of 661 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Slovak)

Currently translated at 68.2% (451 of 661 strings)

Translated using Weblate (Vietnamese)

Currently translated at 99.6% (659 of 661 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Najdi))

Currently translated at 66.5% (440 of 661 strings)

Translated using Weblate (Dutch)

Currently translated at 94.8% (627 of 661 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (French)

Currently translated at 96.3% (637 of 661 strings)

Translated using Weblate (French)

Currently translated at 96.3% (637 of 661 strings)

Translated using Weblate (Turkish)

Currently translated at 25.0% (1 of 4 strings)

Translated using Weblate (Afrikaans)

Currently translated at 30.4% (201 of 661 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Afrikaans)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 68.3% (452 of 661 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (661 of 661 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 56.8% (372 of 654 strings)

Translated using Weblate (Hindi)

Currently translated at 38.3% (251 of 654 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 52.4% (343 of 654 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 43.4% (284 of 654 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 42.2% (276 of 654 strings)

Translated using Weblate (Arabic (Levantine))

Currently translated at 39.6% (259 of 654 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (654 of 654 strings)

Added translation using Weblate (Afrikaans)

Translated using Weblate (German)

Currently translated at 99.5% (651 of 654 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (654 of 654 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (654 of 654 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (654 of 654 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (654 of 654 strings)

Co-authored-by: Alexthegib <traducoes@skiff.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Fqwe1 <Fqwe1@users.noreply.hosted.weblate.org>
Co-authored-by: Guillaume THOMAS <t.guillaume319@laposte.net>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jay Jay Cabugat <cabugatjayjay@gmail.com>
Co-authored-by: Leon de Klerk <deklerkleon5@gmail.com>
Co-authored-by: LiJu09 <lisojuraj@gmail.com>
Co-authored-by: LiberiBg <matheo.ngn@gmail.com>
Co-authored-by: Luna712 <hanstavo1@gmail.com>
Co-authored-by: Murat Han <murathancw@gmail.com>
Co-authored-by: Nepx <anandabaskara@outlook.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Ranforingus <ranforingus@hotmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sam Cooper <samcooper838@gmail.com>
Co-authored-by: Samiul Islam <samiulislamsharan@gmail.com>
Co-authored-by: SehrGuterCode <philemonpfeiffer@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: maxim <maximtested@gmail.com>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: 跨性别 <github@lgbt.sh>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/af/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ars/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/af/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/tr/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane
2023-11-26 02:07:17 +01:00
firelight fa7ebc05b3
Refix youtube
This reverts commit df0122c146.
2023-11-21 22:47:01 +01:00
IndusAryan df0122c146
fix: bump rhino js and upgrade desugaring level (#774)
* fix and bump rhino js

* upgrade desugaring level

* uppercase run to Run
2023-11-18 14:31:41 +00:00
IndusAryan b49368100b
upgrade gradle (#775) 2023-11-18 14:31:27 +00:00
Sofie 0077cebaa6
fixed AesHelper (#773)
Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-11-18 14:30:56 +00:00
IndusAryan a2085202ec
refactor: remove kapt and it's annotation processor, clean gradle, upgrade build-dir deprecation (#764)
* remove kapt and its annotation processor

* cleanup

* change deprecated builddir
2023-11-15 17:31:02 +01:00
CranberrySoup 765071ebef
Fixed flag and name for Levantine Arabic and Najdi Arabic (#770) 2023-11-15 17:30:29 +01:00
self-similarity e11d36aed8
Save selected subtitle language (#765) 2023-11-12 16:36:21 +01:00
Luna712 5bf2b4ead2
Massive changes to account flow (#741)
* Massive changes to account flow
2023-11-11 23:47:23 +01:00
Cloudburst de61501b22
Update prerelease.yml 2023-11-11 17:45:10 +01:00
Cloudburst 685884e67f fix makeJar task 2023-11-11 17:40:47 +01:00
Luna712 6db295a799
Upgrade gradle (#726) 2023-11-11 17:30:36 +01:00
self-similarity 2b60e3a893
Fix faulty automatic subtitle selection (#760) 2023-11-10 23:49:37 +00:00
Luna712 3adf036135
Fix some deprecations and other warnings (#750)
* Fix some deprecations and other warnings
2023-11-10 23:48:53 +00:00
IndusAryan c4aab5e5a8
feat: make cloudstream fast boi, ksp migration (#689)
* migrate from kapt to ksp

* fook codefactor
2023-11-10 17:02:51 +01:00
KingLucius 7e2908c0bb
Fix top bar in Extensions & Test settings (#753) 2023-11-10 15:36:38 +01:00
Sofie 22a0c25d83
extractor: fixed Rabbitstream (#757)
* Extractor: added Rabbitstream

* Extractor: added Rabbitstream

* fixed Rabbitstream

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-11-10 15:28:27 +01:00
self-similarity 11136fe63d
Fix selecting sources in cast (#752) 2023-11-05 22:33:11 +00:00
Luna712 a6786aaf98
Add done button for when creating new PINs (#742)
* Add done button for when creating new PINs

* Cleanup
2023-11-02 23:28:25 +00:00
Luna712 5b0cbbf09f
Use nicer grid layout for account select on TV (#737) 2023-11-02 21:14:16 +01:00
IndusAryan 6a8c251013
bump navigation lib (#749) 2023-11-02 21:07:34 +01:00
KingLucius 908f83c50e
Fix scroll for Library TV layout (#695)
* Fix scroll for Library TV layout

* Fixed without NestedScrollView
2023-11-02 21:03:00 +01:00
recloudstream[bot] 6f40d2750f chore(locales): fix locale issues 2023-11-02 19:59:11 +00:00
Weblate (bot) 199f5b3a9d
Translations update from Hosted Weblate (#681)
Co-authored-by: Ahmed Abd El-Fattah <a.aelfattah5@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Fqwe1 <Fqwe1@users.noreply.hosted.weblate.org>
Co-authored-by: Giuseppe Terrana <terranagiuseppe03@gmail.com>
Co-authored-by: Luna712 <142361265+Luna712@users.noreply.github.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
2023-11-02 20:58:52 +01:00
KingLucius 6ce9f29331
Fix settings top bar on TV (#738) 2023-11-02 20:50:49 +01:00
firelight 8b73c35e43
faster account skip startup 2023-10-31 00:34:01 +01:00
Luna712 65313b4579
Add account selection activity and support profile locks (#736) 2023-10-31 00:32:01 +01:00
IndusAryan a8fdf5e8f2
remove useless parent (#735) 2023-10-30 15:25:50 +00:00
Luna712 87c5aada8f
Bump androidx.preference:preference-ktx (#734) 2023-10-29 16:35:48 +00:00
Luna712 f0e429436f
Use TV results layout on emulator (#710)
* Use TV results layout on emulator

* Add subscription support to emulator

* Update
2023-10-29 01:20:04 +02:00
self-similarity 137d833d4a
Improved Simkl autosync and fixed syncing seasons (#722)
* Improved simkl autosync and fixed syncing seasons
2023-10-29 00:55:49 +02:00
Luna712 b2e0b7dec8
Fix "Multiple substitutions specified in non-positional format" (#727) 2023-10-29 00:52:58 +02:00
Luna712 d542febcda
Reload library when deleting bookmarks (#725) 2023-10-29 00:41:19 +02:00
Luna712 f0ebfa47c8
Bump material to 1.10.0 (#728) 2023-10-29 00:40:20 +02:00
Luna712 51a877f405
Fix some strings (#730) 2023-10-29 00:29:16 +02:00
Luna712 4b93524e57
Convert the rest of SingleSelectionHelper to ViewBinding (#724) 2023-10-26 02:15:50 +02:00
firelight ef36bccc90
Delete old MultiAnimeProvider.kt (#717) 2023-10-26 02:10:08 +02:00
Luna712 968bd59188
Warn of potential duplicates when adding to library (#691) 2023-10-26 02:09:21 +02:00
Luna712 e4ba852007
Use bottom dialogs for synopsis (#709)
* Use bottom dialogs for synopsis

* Add bottomTextDialog
2023-10-25 16:43:29 +02:00
Luna712 504258bf15
Show confirm exit dialog on emulator layout (#704) 2023-10-23 18:42:17 +02:00
KingLucius 48053164dc
Old APIs focus fixes (#692)
* Movie button focus fix in TV layout

* Cast item focusable in old API

* Media description focus fix in old API

* Switch account button focus fix in old APi
2023-10-23 18:38:53 +02:00
Luna712 2a4468eb44
Add more info on homepage to emulator layout (#698)
* Add more info on homepage to emulator layout

* Support for continue watching and bookmarks

It does some manual changes to avoid having to duplicate the entire layout for minor changes
2023-10-23 18:33:44 +02:00
Luna712 5153a74d4f
Library/LocalList: enable subscriptions on emulator layout (#702) 2023-10-23 18:21:32 +02:00
KingLucius 138dea88c4
Poster cropped at 20% from Top (#693) 2023-10-23 18:16:48 +02:00
IndusAryan eb58cb1184
fix crash when navigation graph is null (#706) 2023-10-23 18:11:05 +02:00
firelight c9bffef7cb
Merge pull request #690 from Luna712/locallist-sort
Enable sorting by updated date in LocalList
2023-10-20 13:31:46 +00:00
IndusAryan a7a6f2282a
Update build.gradle.kts (#694) 2023-10-17 19:13:29 +00:00
Luna712 8ed7418fe4 Enable sorting by updated date in LocalList 2023-10-14 10:30:45 -06:00
Luna712 3cb2196e62
Add favorites (#682)
* Add favorites
2023-10-14 01:02:12 +02:00
KingLucius 7e9d1ded7f
Larger top poster in TV loading layout (#685) 2023-10-14 00:54:34 +02:00
Luna712 b7322ffb19
Add clear search query icons (#687) 2023-10-14 00:44:51 +02:00
CranberrySoup fd1620f3d7
Fix unresponsive settings (#688)
* Lower targetSdk to get all installed packages

* Update sdk version

* Let's not be too radical

* Many fixes

* Revert targetSdk

* Make account homepage persistent

* Update mobile_navigation.xml

* Update SettingsFragment.kt
2023-10-14 00:34:26 +02:00
KingLucius fc8c0e809d
Focus fixes for old devices (#686)
- Fix Library on TV main buttons focus.
- Quick search back button focus.
2023-10-12 17:56:54 +00:00
self-similarity 1ccd3d732d
Reduce image cache to 100mb (#683)
* Reduce image cache to 100mb
2023-10-12 01:06:22 +02:00
LagradOst bb6a17e23c resize images for lower mem footprint 2023-10-11 18:31:46 +02:00
recloudstream[bot] 2f2bbd7d88 chore(locales): fix locale issues 2023-10-10 20:19:06 +00:00
Sir Aguacata 749d131099
Added new primary colors for comfort (#653) 2023-10-10 22:18:34 +02:00
Weblate (bot) de6dfec452
Translations update from Hosted Weblate (#596)
Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Antonio N <antonioenpidev@gmail.com>
Co-authored-by: Beabfekad Zikie <beabfekadz@gmail.com>
Co-authored-by: Beach Cow <Beachcow@skiff.com>
Co-authored-by: Boz Osman <nachodev@proton.me>
Co-authored-by: Cait Martin Newnham <85128509+helloiamcait@users.noreply.github.com>
Co-authored-by: Carlos Luiz <ecarlos-luiz@hotmail.com>
Co-authored-by: Chi Uma <jivanov.2048@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Dan <jonweblin2205@protonmail.com>
Co-authored-by: Don Apis <apisapisapis@gmail.com>
Co-authored-by: GobinathAL <gobinathal8@gmail.com>
Co-authored-by: Gyuri Bajzik <bajzikgy@gmail.com>
Co-authored-by: Joel Brink <joel.brink.handy@gmail.com>
Co-authored-by: John <yes20866@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mubarek Seyd Juhar <mubareksd@gmail.com>
Co-authored-by: Muhammad Fahad Khan <itxmfahadkhan@gmail.com>
Co-authored-by: Pizza Party <paol.m@proton.me>
Co-authored-by: Radoslav Lelchev <rlelchev@abv.bg>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Roi Gabay <roigby@gmail.com>
Co-authored-by: Sam Cooper <samcooper838@gmail.com>
Co-authored-by: Samiul Islam <samiulislamsharan@gmail.com>
Co-authored-by: ShareASmile <aapshergill@gmail.com>
Co-authored-by: Skrripy <Skrripy@users.noreply.hosted.weblate.org>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: esfzzddfse <esfzzddfse@proton.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: l <thisuserooo@gmail.com>
Co-authored-by: mbottari <mbottari@quantum-systems.com>
Co-authored-by: pedrolinharesmoreira <pedrolinhares@unifei.edu.br>
Co-authored-by: shivashranz <shivatheboss11@gmail.com>
Co-authored-by: tabtomi8 <tabtomi88@gmail.com>
Co-authored-by: ßozo Mamed <bozo-mamed-27@hotmail.com>
Co-authored-by: Влад Николаев <vladnic1990@gmail.com>
2023-10-10 22:18:21 +02:00
LagradOst b4da93c1de revert jackson 2023-10-10 21:45:36 +02:00
LagradOst dd45ac9e8a reverted to android 14 -> 13 2023-10-10 20:49:04 +02:00
LagradOst b47209483a reverted to instant outline 2023-10-10 18:05:31 +02:00
self-similarity 91b195241e
Automatic backups (#592)
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
2023-10-10 17:19:27 +02:00
KingLucius abbad1bc94
Delete Focus frame from empty Downloads list & Search TV Layout (#675)
* Delete Focus frame in search TV layout

* Delete focus frame for empty Downloads list

* Chip rounded stroke frame
2023-10-10 17:17:18 +02:00
KingLucius b120a7bce2
Library on TV (#663)
* implementation for Library on TV
2023-10-10 17:16:35 +02:00
Luna712 5b4fd8d77d
Fix issue where DownloadedPlayerActivity interferes with MainActivity (#674)
* Fix issue where DownloadedPlayerActivity interferes with MainActivity
2023-10-10 17:05:34 +02:00
LagradOst d277d8a9aa bump upstream 2023-10-10 16:56:30 +02:00
LagradOst 33eb3a3b29 lib fix2 2023-10-07 21:48:24 +02:00
LagradOst f14557fe6a lib fix 2023-10-07 01:54:34 +02:00
LagradOst 77294dc68e cleanup 2023-10-07 01:39:30 +02:00
Luna712 0a327ccbda
Reload library when reloading home (#656)
So that library is reloaded when switching accounts.

Fixes #650
2023-10-06 23:50:31 +02:00
LagradOst 177b1e47f3 added extra logging 2023-10-04 11:33:55 +02:00
Luna712 3f5119525c
Make library preferences account specific (#649) 2023-10-03 22:59:26 +02:00
Luna712 b5d4c3bd27
Make player preferences account specific (#646) 2023-10-03 19:26:56 +02:00
Luna712 cc00e73e16
Make homepage preferences account specific (#647)
* Make homepage preferences account specific

* Fix accidentally removed whitespace

* Fix in setkey
2023-10-03 19:25:31 +02:00
Luna712 462073bd74
Make search prefs account specific (#640) 2023-10-03 16:56:38 +02:00
LagradOst 08060314ad preview seekbar m3u8 2023-10-03 16:50:34 +02:00
Luna712 1d90858f64
Make search history account specific (#638)
* Make search history account specific

* Update for clear history
2023-10-02 21:04:40 +02:00
LagradOst bd05a67f26 preview seekbar 2023-10-02 17:44:06 +02:00
KingLucius bb8cbb5167
More Amazon FireTV focus fixes (#636)
* cast item: mimic the same focus as ATV

* Source & Subtitles priority focus

* Subtitles sync focus

* Account management focus fixes
2023-10-01 01:26:07 +02:00
KingLucius 16c2290090
Amazon FireTV focus fixes (#635)
* Fix quick search button focus

* Switch profile button focus

* Cast & Recommendations focus

* Player: Profiles settings focus

* Player: Subtitles encoding settings focus

* profile selection: card item focus

* Search history item selectable & deleteable

* Search: search filter button next focus fix
2023-09-28 12:22:51 +02:00
KingLucius 194678c419
Player Source & Subs navigation change (#633) 2023-09-28 12:21:03 +02:00
Osten 0351053d80
Readded downloads to tv 2023-09-25 22:57:18 +02:00
Sofie 74060e7da3
Chillx: fix key (#628) 2023-09-25 13:48:35 +02:00
IndusAryan 1e2a11d6e4
refactor: speedostream and newpipe, tmdb update (#632)
* migrate speedostream (yomovies)

* update tmdb and newpipe
2023-09-25 13:48:05 +02:00
CranberrySoup b8917ffa39
Fix episode layout when using RTL language (#631)
* Fix episode layout when using RTL language
2023-09-25 11:40:58 +02:00
CranberrySoup d4fff7cee6
Add homepage search on TV (#618)
* Add search button on homepage for TV
2023-09-21 22:50:31 +02:00
LagradOst 527a6388a9 small fix 2023-09-21 22:46:23 +02:00
CranberrySoup 15333123cd
TV UI fixes (#612)
* TV UI fixes
2023-09-18 23:22:39 +02:00
LagradOst 2ae5b6cefb fixed the fucking updater 💀 2023-09-18 22:28:26 +02:00
LagradOst 0d2a19b350 bump 2023-09-17 20:38:59 +02:00
LagradOst bff9727f96 Merge remote-tracking branch 'origin/master' 2023-09-17 20:35:11 +02:00
LagradOst a82059cb57 fix 2023-09-17 20:35:01 +02:00
CranberrySoup 627c1bb223
Many UI fixes (#606)
* Lower targetSdk to get all installed packages

* Update sdk version

* Let's not be too radical

* Many fixes

* Revert targetSdk

* Make account homepage persistent
2023-09-16 00:30:34 +02:00
CranberrySoup 24977a8d62
Potential fix for crash loops (#608) 2023-09-15 22:47:59 +02:00
LagradOst 6957a8f95d bump 2023-09-14 20:30:44 +02:00
Sofie 2bed79b1f1
Update Gofile.kt (#600) 2023-09-14 12:53:54 +02:00
self-similarity a5450e5da2
More robust player release (#601) 2023-09-14 12:53:35 +02:00
LagradOst 8fe34d3d2a Merge remote-tracking branch 'origin/master' 2023-09-11 23:05:47 +02:00
LagradOst 7d6ba8c7a4 tv changes for better centering + bigger text + better contrast 2023-09-11 23:05:10 +02:00
self-similarity 2baa75496e
Fix opensubtitles (#598)
* Fix OpenSubtitles
2023-09-11 20:13:42 +02:00
Sofie 01e7acdeac
getTracker: switched to anilist api (#593)
* getTracker: switched to anilist api

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-09-11 14:31:11 +02:00
LagradOst 10bc688eaf fixed tracker on dub 2023-09-11 14:29:30 +02:00
LagradOst 7f7c81828a added UI event for seekbar 2023-09-11 13:37:11 +02:00
KingLucius f6b0ea8dfa
Stream button type switch support (#597)
* Stream button type switch support

* Hide Hls playlist switch
2023-09-10 15:31:01 +02:00
LagradOst 0afbc90cd2 fixed last fix 2023-09-09 23:57:18 +02:00
LagradOst 85c4c74222 fixed shitty external extractor code 2023-09-09 23:53:35 +02:00
LagradOst b6e99d7358 backend change for events in player 2023-09-09 23:18:21 +02:00
self-similarity 130cc16e25
Simkl API optimizations (#581)
* Fix episode removal in simkl

* Simkl API optimizations
2023-09-09 00:13:04 +02:00
recloudstream[bot] 1629db2fc9 chore(locales): fix locale issues 2023-09-08 08:01:34 +00:00
Weblate (bot) f05c65cf5c
Translated using Weblate (Odia) (#574)
Currently translated at 39.5% (249 of 630 strings)

Translated using Weblate (Odia)

Currently translated at 25.0% (1 of 4 strings)

Translated using Weblate (Odia)

Currently translated at 38.8% (245 of 630 strings)

Translated using Weblate (German)

Currently translated at 99.8% (629 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Tamil)

Currently translated at 20.9% (132 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (630 of 630 strings)

Translated using Weblate (Croatian)

Currently translated at 99.8% (629 of 630 strings)

Translated using Weblate (Croatian)

Currently translated at 99.3% (626 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Najdi))

Currently translated at 54.9% (346 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (630 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (French)

Currently translated at 100.0% (630 of 630 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Hungarian)

Currently translated at 85.7% (540 of 630 strings)

Translated using Weblate (Romanian)

Currently translated at 95.7% (603 of 630 strings)

Translated using Weblate (Arabic (Najdi))

Currently translated at 50.1% (316 of 630 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (630 of 630 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 96.1% (606 of 630 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Arabic (Najdi))

Currently translated at 44.9% (283 of 630 strings)

Translated using Weblate (Arabic (Najdi))

Currently translated at 39.6% (250 of 630 strings)

Translated using Weblate (Arabic (Najdi))

Currently translated at 39.5% (249 of 630 strings)

Translated using Weblate (German)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (German)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (German)

Currently translated at 99.8% (629 of 630 strings)

Translated using Weblate (German)

Currently translated at 99.8% (629 of 630 strings)

Translated using Weblate (Arabic (Najdi))

Currently translated at 33.4% (211 of 630 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (630 of 630 strings)

Translated using Weblate (German)

Currently translated at 99.8% (629 of 630 strings)

Translated using Weblate (German)

Currently translated at 99.8% (629 of 630 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Arabic (Najdi))

Currently translated at 32.0% (202 of 630 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 91.5% (577 of 630 strings)

Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Arabic (Najdi))

Currently translated at 23.9% (151 of 630 strings)

Added translation using Weblate (Arabic (South Levantine))

Translated using Weblate (Amharic)

Currently translated at 14.9% (94 of 630 strings)

Translated using Weblate (Tigrinya)

Currently translated at 15.0% (95 of 630 strings)

Added translation using Weblate (Amharic)

Added translation using Weblate (Tigrinya)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Hungarian)

Currently translated at 85.2% (537 of 630 strings)

Translated using Weblate (Hungarian)

Currently translated at 81.4% (513 of 630 strings)


















Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/am/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ars/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ta/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ti/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/ar_SA/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/uk/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane

Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Cait Martin Newnham <85128509+helloiamcait@users.noreply.github.com>
Co-authored-by: Carlos Luiz <ecarlos-luiz@hotmail.com>
Co-authored-by: Chi Uma <jivanov.2048@gmail.com>
Co-authored-by: GobinathAL <gobinathal8@gmail.com>
Co-authored-by: Gyuri Bajzik <bajzikgy@gmail.com>
Co-authored-by: Joel Brink <joel.brink.handy@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Mubarek Seyd Juhar <mubareksd@gmail.com>
Co-authored-by: Sam Cooper <samcooper838@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: mbottari <mbottari@quantum-systems.com>
Co-authored-by: pedrolinharesmoreira <pedrolinhares@unifei.edu.br>
Co-authored-by: tabtomi8 <tabtomi88@gmail.com>
2023-09-08 10:01:11 +02:00
IndusAryan 4ddd78ebb6
fook jitpack (#595) 2023-09-08 10:00:00 +02:00
LagradOst 49731cd699 changed drm API a bit 2023-09-06 22:42:22 +02:00
LagradOst 3fe247fb19 added drm player support 2023-09-06 20:53:43 +02:00
CranberrySoup 0839775172
Upgrade SDK (#590)
* Update sdk version

* Let's not be too radical
2023-09-04 22:36:36 +02:00
LagradOst 6211b02e85 switched from isM3u8 to ExtractorLinkType 2023-09-03 23:32:43 +02:00
Sofie 9c991f2abd
extractor: fix chillx (#583)
* Extractor: added Rabbitstream

* Extractor: added Rabbitstream

* extractor: fix Chillx

* comply

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-09-02 00:32:18 +02:00
LagradOst 6089cbc484 fixed subs on downloads 2023-08-30 00:52:34 +02:00
LagradOst ce1f48978b fixed download error 2023-08-28 20:56:58 +02:00
LagradOst f01820059b delete resume watching + delete bookmarks buttons. fixed backup crash 2023-08-27 19:07:08 +02:00
LagradOst 7d3b8c464e Merge remote-tracking branch 'origin/master' 2023-08-25 23:16:45 +02:00
LagradOst 8193e39b30 bump + refactor 2023-08-25 23:16:34 +02:00
recloudstream[bot] 557003895b chore(locales): fix locale issues 2023-08-25 08:59:37 +00:00
Weblate (bot) d0c03321b9
Translations update from Hosted Weblate (#568)
Co-authored-by: Carlos Luiz <ecarlos-luiz@hotmail.com>
Co-authored-by: Joel Brink <joel.brink.handy@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Mubarek Seyd Juhar <mubareksd@gmail.com>
Co-authored-by: Sam Cooper <samcooper838@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: mbottari <mbottari@quantum-systems.com>
Co-authored-by: tabtomi8 <tabtomi88@gmail.com>
2023-08-25 10:59:18 +02:00
Sofie 2d82480398
fix Rabbitstream (#573)
Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-08-25 10:58:58 +02:00
LagradOst b38a9b1ff5 fuck android 2023-08-24 21:39:05 +02:00
LagradOst 1a4cbcaea0 small fix 2023-08-24 21:17:42 +02:00
LagradOst 9b4701fe91 dont remove keys while this is tested 2023-08-24 18:14:54 +02:00
LagradOst c92ac3e8b3 fixed removal of predownloaded files 2 + permission 2023-08-24 18:13:42 +02:00
LagradOst 39ff6ef8ef Merge remote-tracking branch 'origin/master' 2023-08-24 16:40:09 +02:00
LagradOst 460b1be525 fixed removal of predownloaded files 2023-08-24 16:39:50 +02:00
CranberrySoup 9a1358e295
Lower targetSdk to get all installed packages (#571) 2023-08-24 16:16:33 +02:00
LagradOst 823ffd8708 reverted low api crash handle crashing 2023-08-24 00:25:05 +02:00
LagradOst 5bad6aca35 fixed native crash handle 2023-08-23 23:57:54 +02:00
LagradOst e2502de02c bump acra 2023-08-23 18:43:55 +02:00
LagradOst bac2ee9805 fixed div by zero 2023-08-23 17:08:26 +02:00
LagradOst d436171a2f removed possible duplicate download queue 2023-08-23 06:36:43 +02:00
LagradOst 3ea6b1a8d5 fixed resume download + migrated filesystem to SafeFile 2023-08-23 06:25:06 +02:00
LagradOst afcbdeecc8 changes to downloader for stable resume 2023-08-22 04:00:05 +02:00
LagradOst 4e28e5f8cc fixed not downloading the last 20MiB on mp4 downloader + bump + mb/s notification 2023-08-20 03:58:31 +02:00
LagradOst 1901eb371e Merge remote-tracking branch 'origin/master' 2023-08-20 01:29:57 +02:00
LagradOst c4852ce440 made HSL downloader even faster 2023-08-20 01:29:50 +02:00
self-similarity a3009af4f5
Add Native Crash Handler (#565)
* Add NativeCrashHandler

* Safer init
2023-08-19 21:48:10 +02:00
recloudstream[bot] 6948bf8073 chore(locales): fix locale issues 2023-08-19 19:38:45 +00:00
Weblate (bot) 61ca0a56be
Translations update from Hosted Weblate (#546)
Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Alexthegib <jcwkgxc@nightorb.com>
Co-authored-by: Alexthegib <traducoes@skiff.com>
Co-authored-by: Amir <amearb@duck.com>
Co-authored-by: Astrid <github@astrid.exposed>
Co-authored-by: Carlos Luiz <ecarlos-luiz@hotmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Danilo <danilomaiarochaw@gmail.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Htet Oo Hlaing <htetoh2006@outlook.com>
Co-authored-by: Imprevisible <imprevisible@duck.com>
Co-authored-by: Jan Haider <jan.haider@i-kunden.de>
Co-authored-by: Jimuel Mallari <jimuelmallari284@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: PiterDev <piterzdev@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Rudy Tantono <rudzlong@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: george kitsoukakis <norhorn@gmail.com>
Co-authored-by: infoekcz <Admin@infoek.cz>
Co-authored-by: tuan041 <tuananh163025ttt@gmail.com>
2023-08-19 21:38:29 +02:00
LagradOst 98b6417140 made downloader faster with parallel downloads 2023-08-19 21:37:14 +02:00
LagradOst 10c1ea2f02 Merge remote-tracking branch 'origin/master' 2023-08-19 17:03:47 +02:00
LagradOst b3abf1e45f fixed decryption 2023-08-19 17:03:27 +02:00
IndusAryan f571596bbc
fix: expand resume watching sheet and ft: ripple on profile drawable when pressed (#566)
* add ripple to profile icon on home

* Update HomeParentItemAdapterPreview.kt
2023-08-19 16:04:21 +02:00
LagradOst e20e3dcfd3 fixed some bugs caused by new download update 2023-08-19 04:46:47 +02:00
LagradOst 35e1b8b4dc bump 2023-08-19 01:38:40 +02:00
LagradOst a05616e3e8 fix 2023-08-19 01:37:48 +02:00
LagradOst 56cb3d7181 refactored download system for better preference + bugfixes 2023-08-19 00:48:00 +02:00
IndusAryan e95dc1db2a
fix: cast items recycler (finally) (#564)
* turn cast items visible(tools)

* prevent cast gesture listener from permanent RIP in one lifecycle
2023-08-18 17:46:03 +02:00
LagradOst 8f6e8a8e99 fixed #547
fuck inheritance
2023-08-18 01:46:29 +02:00
IndusAryan 61d63b17d8
chore: acra improvements and media3 bump (#562)
* Acra Bump

* Media3 bump
2023-08-17 23:11:59 +02:00
LagradOst 590c74111c fuck it we ball, m3u8 download is now fixed 2023-08-17 23:10:21 +02:00
LagradOst c2b951a078 fixed #560 lock locks orientation 2023-08-17 01:19:24 +02:00
LagradOst cbaca158fa Merge remote-tracking branch 'origin/master' 2023-08-17 01:00:51 +02:00
LagradOst 20da3807a2 fixed search query for intent 2023-08-17 01:00:43 +02:00
IndusAryan d247640dcf
Play n Dowload button fix for NS*W results. (#557)
* Play n Dowload button fix for NS*W results.

* Revert MainAPI Changes

* Tweaked ResultViewModel
2023-08-16 16:18:15 +02:00
IndusAryan d536dffaf5
Fix Trailers not Working (#559)
* Fix Trailers not Working

* smol tip
2023-08-16 16:15:39 +02:00
self-similarity 4e01d327c6
Fix episode removal in simkl (#555) 2023-08-15 20:37:33 +02:00
LagradOst 4d98690adb small fix to home load 2023-08-15 02:05:07 +02:00
IndusAryan 74867bed1c
Update SpeedoStream.kt (#552)
Fixes YoMovies Provider.
2023-08-13 17:37:36 +02:00
LagradOst 0eb241e6cb fixed fab expand 2023-08-12 23:54:37 +02:00
LagradOst 3ab9e11350 fixed SimklApi subscription 2023-08-12 23:41:53 +02:00
self-similarity d2d2e41fb3
Added Simkl (#548) 2023-08-12 22:25:30 +02:00
LagradOst dd4f4a2b78 should fix an issue with auto_download_plugins_key 2023-08-12 21:52:37 +02:00
LagradOst e43b4808d1 phone fix 2023-08-12 21:23:43 +02:00
LagradOst 3ac462ae96 changed UI a bit for flashbang + fixed crash inf loading bug 2023-08-12 21:20:51 +02:00
self-similarity ecd529f73b
TV UX improvements (#538)
* Update styles.xml
2023-08-12 17:44:35 +02:00
Cloudburst 2d65aefc76 fix values-in 2023-08-10 09:34:29 +02:00
recloudstream[bot] 3af0bf750c chore(locales): fix locale issues 2023-08-09 21:56:47 +00:00
Weblate (bot) 72871c18b5
Translations update from Hosted Weblate (#535)
Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Alexthegib <jcwkgxc@nightorb.com>
Co-authored-by: Alexthegib <traducoes@skiff.com>
Co-authored-by: Amir <amearb@duck.com>
Co-authored-by: Astrid <github@astrid.exposed>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Jan Haider <jan.haider@i-kunden.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: PiterDev <piterzdev@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Rudy Tantono <rudzlong@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: george kitsoukakis <norhorn@gmail.com>
Co-authored-by: infoekcz <Admin@infoek.cz>
2023-08-09 23:56:28 +02:00
Cloudburst 44a2146c12
fix voting api (#544) 2023-08-09 23:44:17 +02:00
Sofie bbbb7c4982
Extractor: added Rabbitstream (#536)
* Extractor: added Rabbitstream

* fix all request

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-08-05 03:11:46 +02:00
self-similarity ca6700e28d
More meaningful errors when adding repositories (#537)
* More meaningful errors when adding repositories
2023-08-04 17:21:20 +02:00
LagradOst 5103ad09dc reverted gradle bump 2023-08-04 17:20:23 +02:00
LagradOst f5c4864a3c tv focus changes + gradle bump + pip crash fix 2023-08-04 05:37:41 +02:00
recloudstream[bot] 653982a6bd chore(locales): fix locale issues 2023-08-02 19:14:54 +00:00
Weblate (bot) 22c0022684
Translations update from Hosted Weblate (#527)
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: PiterDev <piterzdev@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: infoekcz <Admin@infoek.cz>
2023-08-02 21:14:37 +02:00
LagradOst 7e6a28bb99 fixed tv focus issue 2023-08-02 21:00:04 +02:00
Vu Hoan Huy c5f6f36fc7
fix: can not switch subtitle after integrate ffmpeg decoder. (#533)
* Revert "Revert "Use ffmpeg library (#528)" (#532)"

This reverts commit 87d85429f8.

* fix: can not select subtitle
2023-08-02 19:36:05 +02:00
self-similarity 3137a68552
fix player session id (#534) 2023-08-02 19:35:41 +02:00
LagradOst 2475088f76 added local accounts to TV layout 2023-08-02 17:31:55 +02:00
Osten 87d85429f8
Revert "Use ffmpeg library (#528)" (#532)
This reverts commit 32e243ce94.
2023-08-02 17:13:50 +02:00
self-similarity 32e243ce94
Use ffmpeg library (#528) 2023-08-02 05:31:35 +02:00
LagradOst 180987e2d0 added local accounts 2023-08-02 05:30:50 +02:00
LagradOst b06f098447 fixed android tv trailer bug 2023-08-02 02:13:30 +02:00
recloudstream[bot] 6ff4f4c1ce chore(locales): fix locale issues 2023-08-01 14:04:17 +00:00
Weblate (bot) 0afc9f15d2
Translated using Weblate (Swedish) (#522)
Currently translated at 83.1% (518 of 623 strings)

Translated using Weblate (Swedish)

Currently translated at 72.8% (454 of 623 strings)

Translated using Weblate (Croatian)

Currently translated at 99.8% (622 of 623 strings)

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Galician)

Currently translated at 16.6% (104 of 623 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (623 of 623 strings)

Added translation using Weblate (Galician)

Translated using Weblate (Czech)

Currently translated at 100.0% (623 of 623 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (623 of 623 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (623 of 623 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (623 of 623 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Bulgarian)

Currently translated at 92.5% (575 of 621 strings)

Translated using Weblate (German)

Currently translated at 25.0% (1 of 4 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 50.0% (2 of 4 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 50.0% (2 of 4 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.3% (617 of 621 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (English)

Currently translated at 100.0% (4 of 4 strings)

Translated using Weblate (Polish)

Currently translated at 50.0% (2 of 4 strings)

Translated using Weblate (Greek)

Currently translated at 94.5% (587 of 621 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (621 of 621 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Japanese)

Currently translated at 46.3% (288 of 621 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (621 of 621 strings)

Merge remote-tracking branch 'origin/master'

Translated using Weblate (Indonesian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Japanese)

Currently translated at 46.2% (287 of 621 strings)

Translated using Weblate (Bulgarian)

Currently translated at 90.6% (563 of 621 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (621 of 621 strings)























Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/gl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/fastlane/zh_Hans/
Translation: Cloudstream/App
Translation: Cloudstream/Fastlane

Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hristo Hristov <hristov.tanev@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Osten <11805592+LagradOst@users.noreply.github.com>
Co-authored-by: PiterDev <piterzdev@gmail.com>
Co-authored-by: Red Star Over Earth <rs0vere@outlook.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Rudy Tantono <rudzlong@gmail.com>
Co-authored-by: Salif Mehmed <mail@salif.eu>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Thanasis <thanasakis11mail@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: tictactoe <phandinhminh@protonmail.ch>
2023-08-01 16:03:58 +02:00
Jace 827cbbb0b5
Feature: Refactor autodownload plugin to have multiple modes. (#518) 2023-08-01 15:54:15 +02:00
Sofie a8ed8773de
Extractor: fix Gofile and added Userscloud (#523)
* Extractor: added Pixeldrain, Wibufile and fix some extractors

* Extractor: added Moviesapi and fix some extractors

* Extractor: fix Gofile and added Userscloud

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-08-01 15:50:02 +02:00
Osten 363ffa26de
Update README.md 2023-08-01 04:11:20 +02:00
LagradOst 7c60ccdef2 fixed #521 2023-08-01 04:03:43 +02:00
LagradOst d5316bff9b fixed #524 2023-08-01 03:12:32 +02:00
Osten 8dae4c2b0f
Self similarity/master (#525)
* Migrated to Media3

---------

Co-authored-by: self-similarity <137652432+self-similarity@users.noreply.github.com>
2023-08-01 01:25:28 +02:00
recloudstream[bot] 6b87fb7831 chore(locales): fix locale issues 2023-07-31 13:43:46 +00:00
Cloudburst 6c325cf721
Translated using Weblate (Vietnamese) (#513)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hristo Hristov <hristov.tanev@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: PiterDev <piterzdev@gmail.com>
Co-authored-by: Red Star Over Earth <rs0vere@outlook.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Rudy Tantono <rudzlong@gmail.com>
Co-authored-by: Salif Mehmed <mail@salif.eu>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Thanasis <thanasakis11mail@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: tictactoe <phandinhminh@protonmail.ch>
2023-07-31 15:43:25 +02:00
LagradOst 04ef6043b0 fixed small tv issues 2023-07-31 15:35:42 +02:00
Cloudburst 661dfc0927 Revert "bump ver"
This reverts commit 21e5a1e244.
2023-07-30 18:11:47 +00:00
Osten 4b4e006f4a
Merge pull request #507 from recloudstream/viewbindings
Migration to viewbindings
2023-07-30 15:15:44 +02:00
LagradOst 3bdbb35754 alert fix + synchronized + bump + homepage load fix + small focus change 2023-07-30 05:05:13 +02:00
LagradOst c987f7581e major focus fixes 2023-07-28 04:18:28 +02:00
LagradOst c98f35fd94 focus fix + rtl fix 2023-07-27 21:47:42 +02:00
LagradOst a1824c86a3 made tv UI better on resultspage + ep range + focus bugfix 2023-07-26 05:44:37 +02:00
Rex_sa bfb3313137
Add Arabic fastlane (#517)
* add arabic

* add arabic

* add arabic
2023-07-26 04:47:17 +02:00
LagradOst 31da089eb1 testing tag for tv focus + player popup fix 2023-07-25 21:15:10 +02:00
LagradOst 3e4a5bdf4c testing follow focus on tv 2023-07-24 04:02:05 +02:00
Mater Yoda 446f774fb4
added streamoupload extractor (#506)
* added streamoupload extractor
2023-07-24 04:01:50 +02:00
LagradOst 51a6e917b5 testing tv UI 2, NOT FINISHED 2023-07-23 20:10:21 +02:00
LagradOst 35084389a1 testing tv UI, NOT FINISHED 2023-07-23 03:07:24 +02:00
LagradOst 5aa9019d6d changed a bit of TV UI 2023-07-19 20:37:57 +02:00
LagradOst da6577e587 actions java 11 -> 17 & fixed parent job is cancelling message 2023-07-19 18:47:22 +02:00
LagradOst 9755bbacb9 redirected downloadbutton longclick 2023-07-19 17:58:40 +02:00
LagradOst 3ae44d5675 readded download text progress 2023-07-19 17:27:47 +02:00
LagradOst 483ce2854f bump -> 8.0.2 2023-07-19 17:04:29 +02:00
LagradOst 21e5a1e244 bump ver 2023-07-19 02:06:55 +02:00
LagradOst ed0d374721 removed synthetic by removing ResultFragment 2023-07-19 01:51:17 +02:00
LagradOst 4fcf396591 bug fix + white filler button 2023-07-18 22:35:17 +02:00
LagradOst 03d50a943a result -> result specific 2023-07-18 22:18:14 +02:00
LagradOst d5c42f7d5a more result bindings + player 2023-07-18 03:55:00 +02:00
LagradOst 4f28aef8f2 GeneratorPlayer -> viewbinding, AbstractPlayerFragment -> findViewById,
parity between player_custom_layout_tv, player_custom_layout and  fragment_player, fragment_player_tv
2023-07-17 21:47:27 +02:00
LagradOst f30506a394 homeparentitemadapterpreview -> viewbinding 2023-07-17 20:25:41 +02:00
LagradOst 4d6e64adb6 weakrefrence activity for cleaner code + HomeParentItemAdapterPreview viewmodel + more stuff in viewmodel 2023-07-17 03:32:41 +02:00
LagradOst afadf121f4 testing leaks 2023-07-16 02:25:36 +02:00
LagradOst a2a4da5a29 moved download view to nicer button 2023-07-15 23:43:09 +02:00
LagradOst 6bc5d86ff9 fix to color + fixed title on cards 2023-07-15 20:38:06 +02:00
LagradOst f209c7286e more viewbindings + result fix + more tests 2023-07-15 20:00:09 +02:00
LagradOst c946115900 mini fix 2023-07-15 03:27:25 +02:00
LagradOst 04f52f4a6d added tests for layout 2023-07-15 03:25:32 +02:00
LagradOst 273a947f8e more views 2023-07-14 22:05:13 +02:00
LagradOst 647e91bc4b more views + MainActivity viewbindings 2023-07-14 21:43:46 +02:00
Osten c3296f3210
fixed bug with source priority 2023-07-14 21:33:14 +02:00
LagradOst 166a21f74e more views -> viewbinding 2023-07-14 02:28:49 +02:00
LagradOst 05a0d3cd81 migrated some items to viewbindings + removed Some<T> 2023-07-13 23:18:37 +02:00
Sofie 927453d9fe
Extractor: added Moviesapi and fix some extractors (#504)
* Extractor: added Pixeldrain, Wibufile and fix some extractors

* Extractor: added Moviesapi and fix some extractors

---------

Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-07-12 18:15:25 +02:00
recloudstream[bot] 9237817bd3 chore(locales): fix locale issues 2023-07-11 06:36:01 +00:00
Hosted Weblate 525bf8d861 Translated using Weblate (Odia)
Currently translated at 38.9% (242 of 621 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Turkish)

Currently translated at 99.5% (618 of 621 strings)

Translated using Weblate (Turkish)

Currently translated at 99.5% (618 of 621 strings)

Translated using Weblate (German)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Malay)

Currently translated at 20.4% (127 of 621 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (German)

Currently translated at 99.8% (620 of 621 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate (Odia)

Currently translated at 39.1% (239 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Hebrew)

Currently translated at 94.9% (579 of 610 strings)

Translated using Weblate (Malay)

Currently translated at 18.1% (111 of 610 strings)

Translated using Weblate (Urdu)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 39.0% (238 of 610 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 46.0% (281 of 610 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 96.7% (590 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 39.0% (238 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 38.6% (236 of 610 strings)

Translated using Weblate (Bengali)

Currently translated at 38.1% (233 of 610 strings)

Co-authored-by: Aftabuzzaman <Leemon432@gmail.com>
Co-authored-by: Aitor Salaberria <trslbrr@gmail.com>
Co-authored-by: Alexthegib <jcwkgxc@nightorb.com>
Co-authored-by: Andreas <andreas.blindheim.koppen@gmail.com>
Co-authored-by: Bananenbrot <keram2810@outlook.de>
Co-authored-by: BluTiger <beqirstafa@gmail.com>
Co-authored-by: Clxff H3r4ld0 <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Dan <jonweblin2205@protonmail.com>
Co-authored-by: Efe Devirgen <efedevirgen@gmail.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Ettore Atalan <atalanttore@googlemail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kai <rafahdamin@gmail.com>
Co-authored-by: Levi Klippel <leviklippel@gmail.com>
Co-authored-by: Nathan Khutorskoy <natank44@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: Sufyan Zahoor Jutt <sufyanpahore@gmail.com>
Co-authored-by: enescan201 <enescan14083@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/he/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ms/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ur/
Translation: Cloudstream/App
2023-07-11 08:35:42 +02:00
Sofie 847957362f
Extractor: added Pixeldrain, Wibufile and fix some extractors (#502)
Co-authored-by: Sofie99 <Sofie99@gmail.com>
2023-07-10 01:52:03 +02:00
Nexus 51c1089162
Updated some of the extractor Domains (#495)
* Update AsianLoad.kt

Asianload domain changed

* Update Hxfile.kt

Some of the old url fix

* Update Moviehab.kt

* Update MultiQuality.kt

* Update AsianLoad.kt

* Update Hxfile.kt

* Update MultiQuality.kt
2023-07-02 19:41:19 +02:00
Nexus da0be63b7c
Update ByteShare.kt (#494)
* Update ByteShare.kt
2023-06-30 18:19:52 +02:00
Saksham Shekher a95fcfc9db
SpeedoStream update (#493) 2023-06-27 14:54:05 +02:00
imgbot[bot] 40a963588f
[ImgBot] Optimize images (#485)
*Total -- 351.66kb -> 337.87kb (3.92%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2023-06-15 21:45:03 +02:00
LagradOst 906f1fdc9a
Fixed skip loading (#484)
* Added quality profiles

* Better quality selection

* Added profile bg and fixed some sources

* Properly fixed skip loading

* Extra safety

---------

Co-authored-by: Lag <>
2023-06-15 00:42:42 +02:00
LagradOst b5566af401
Added quality profiles (#414)
* Added quality profiles

* Better quality selection

* Added profile bg and fixed some sources (#483)

Co-authored-by: Blatzar <>

---------

Co-authored-by: Lag <>
Co-authored-by: Osten <11805592+LagradOst@users.noreply.github.com>
2023-06-14 19:30:39 +02:00
Hexated 0d431fd508
fixed Stramsb & Voe (#470) 2023-05-20 23:37:17 +00:00
recloudstream[bot] b115817357 chore(locales): fix locale issues 2023-05-14 16:20:11 +00:00
Hosted Weblate c0a8461b87 Translated using Weblate (Kannada)
Currently translated at 36.2% (221 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 38.5% (235 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 26.3% (161 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 22.6% (138 of 610 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: deepu2 <deepuhsdeepak@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translation: Cloudstream/App
2023-05-14 18:19:51 +02:00
Shif-Jess 8c9d52bc0e
Added new Extractors (#461) 2023-05-14 18:19:04 +02:00
recloudstream[bot] 0f00b1baf0 chore(locales): fix locale issues 2023-05-10 07:27:01 +00:00
Cloudburst ae1aaa3d7d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Hindi)

Currently translated at 38.3% (234 of 610 strings)

Translated using Weblate (Japanese)

Currently translated at 46.5% (284 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 21.4% (131 of 610 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Persian)

Currently translated at 22.1% (135 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 21.3% (130 of 610 strings)

Translated using Weblate (Odia)

Currently translated at 18.1% (111 of 610 strings)

Co-authored-by: 1 <zagukya@goatmail.uk>
Co-authored-by: Adarsh0-s <jeff19whisper@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: KING APPS <kiperking1@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: jhihyu lin <thomas.jy.lin@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/or/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hant/
Translation: Cloudstream/App
2023-05-10 07:26:34 +00:00
Cloudburst b37aa55343
remove strings.xml comment 2023-05-10 09:16:24 +02:00
jhih_yu 77d4ecd7c6
Fix Traditional Chinese (zh-rTW) display name (#467) 2023-05-10 09:14:01 +02:00
Cloudburst 3b21ec3794
NewPipeExtractor:v0.22.6 -> NewPipeExtractor:master-SNAPSHOT (#468) 2023-05-10 09:13:48 +02:00
recloudstream[bot] 386ce75df1 chore(locales): fix locale issues 2023-05-03 20:30:03 +00:00
Hosted Weblate 27155e0f7e Update translation files
Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Hungarian)

Currently translated at 83.6% (510 of 610 strings)

Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translation: Cloudstream/App
2023-05-03 22:29:45 +02:00
recloudstream[bot] 3121b5b123 chore(locales): fix locale issues 2023-05-03 20:17:55 +00:00
Hosted Weblate 8a5ddcd126 Added translation using Weblate (Odia)
Translated using Weblate (Vietnamese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Latvian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Vietnamese)

Currently translated at 99.3% (606 of 610 strings)

Translated using Weblate (Malayalam)

Currently translated at 41.4% (253 of 610 strings)

Translated using Weblate (Vietnamese)

Currently translated at 96.3% (588 of 610 strings)

Translated using Weblate (Hungarian)

Currently translated at 83.6% (510 of 610 strings)

Translated using Weblate (Slovak)

Currently translated at 72.4% (442 of 610 strings)

Translated using Weblate (Slovak)

Currently translated at 44.9% (274 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Slovak)

Currently translated at 34.2% (209 of 610 strings)

Co-authored-by: Bojtár Zsömle <bence.bojtar@gmail.com>
Co-authored-by: Dinh Nguyen <dinhitcom@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Juraj Liso <lisojuraj@gmail.com>
Co-authored-by: Khoi <phamkhoi06@duck.com>
Co-authored-by: Kiên Tài <kientai142@gmail.com>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: akku vijay <akkuvijay@duck.com>
Co-authored-by: liva <livinja@proton.me>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/lv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translation: Cloudstream/App
2023-05-03 22:17:37 +02:00
Cloudburst 42bf8ed08e
Update newpipe (#462) 2023-05-03 22:16:35 +02:00
Horis fb3576ea52
fix video download (#453) 2023-04-21 13:56:17 +02:00
recloudstream[bot] 56a680fa9c chore(locales): fix locale issues 2023-04-21 11:56:05 +00:00
Hosted Weblate 633aef8783 Translated using Weblate (Macedonian)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Korean)

Currently translated at 93.6% (571 of 610 strings)

Translated using Weblate (Korean)

Currently translated at 87.5% (534 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Korean)

Currently translated at 31.4% (192 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Added translation using Weblate (Korean)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (German)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (French)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (German)

Currently translated at 99.6% (608 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.6% (608 of 610 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.8% (554 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Romanian)

Currently translated at 95.4% (582 of 610 strings)

Translated using Weblate (Romanian)

Currently translated at 75.0% (458 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.4% (552 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.8% (231 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Added translation using Weblate (Arabic (Najdi))

Translated using Weblate (Latvian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Japanese)

Currently translated at 46.2% (282 of 610 strings)

Translated using Weblate (Macedonian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Latvian)

Currently translated at 30.4% (186 of 610 strings)

Added translation using Weblate (Latvian)

Translated using Weblate (German)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (German)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Macedonian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 99.8% (609 of 610 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (227 of 610 strings)

Co-authored-by: AHOHNMYC <lqwh2h2cwa@protonmail.com>
Co-authored-by: Aitor Salaberria <trslbrr@gmail.com>
Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Alexthegib <jcwkgxc@nightorb.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Anurag <anuragrajanp@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Clxff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: FastAct <alex.rijckaert@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Synertry <jonny.somrak@gmail.com>
Co-authored-by: Tang Yin <bingyuanshiye@126.com>
Co-authored-by: The Unbreakable Spirit <U2001072@rajagiri.edu.in>
Co-authored-by: Turgay Doğru <turgaydogru@gmail.com>
Co-authored-by: Vrwi <jurgisbums@gmail.com>
Co-authored-by: Zaki Bouta <zbouta02@gmail.com>
Co-authored-by: edgolron <edgolron@tutanota.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: jinu147 <nesqea20@gmail.com>
Co-authored-by: stojkovskistefan <stefanstojkovski@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ko/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/lv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-04-21 13:55:42 +02:00
Cloudburst a12d234ef4 fix shortcodes 2023-04-21 13:54:58 +02:00
reduplicated bdb45b69d3 pip fixes 2023-04-11 18:04:24 +02:00
reduplicated 4449347593 bump 2023-04-11 17:32:55 +02:00
Shif-Jess b356ad9e61
CS3IPlayer: fix buffer lost when seeked to backward (#448)
* CS3IPlayer: fix buffer lost when seeked to backward

* changed BUFFER_MS
2023-04-11 09:46:39 +00:00
Sarlay 94e7eb8e9d
added a mirror to streamsb (#439) 2023-04-09 14:21:41 +00:00
Shif-Jess 4f9016713f
CS3Player: fixed ERROR_CODE_BEHIND_LIVE_WINDOW (#447) 2023-04-09 09:37:27 +02:00
recloudstream[bot] 4ed65f8e07 chore(locales): fix locale issues 2023-03-29 13:27:53 +00:00
Hosted Weblate 7317278f57 Translated using Weblate (Macedonian)
Currently translated at 97.7% (596 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Romanian)

Currently translated at 71.4% (436 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 90.1% (550 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Hungarian)

Currently translated at 83.9% (512 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 99.6% (608 of 610 strings)

Translated using Weblate (Italian)

Currently translated at 99.6% (608 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Hungarian)

Currently translated at 60.9% (372 of 610 strings)

Co-authored-by: Alexandru <negrualexandru52@gmail.com>
Co-authored-by: Alexthegib <jcwkgxc@nightorb.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Clxff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: FastAct <alex.rijckaert@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: ZsoltiHUB <zsoltizsolti043@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: stojkovskistefan <stefanstojkovski@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translation: Cloudstream/App
2023-03-29 15:27:35 +02:00
Shif-Jess 53293dadd0 fixed streamsb 2023-03-29 15:27:06 +02:00
LagradOst 67b0549fd2
remove images 2023-03-21 21:01:47 +00:00
Osten 52d495f425
Update README.md 2023-03-21 20:50:13 +00:00
Cloudburst 0cbee70683
[skip ci] Update locales.py 2023-03-19 12:51:54 +01:00
Lag 4235c826a5 Better focus on Android TV
(Thank you ocean for reporting)
2023-03-18 23:55:58 +01:00
Cloudburst 5245eff6e1
[skip ci] fix xml header being slightly wrong 2023-03-18 09:22:07 +01:00
Lag 9c40abc4d3 Added player intent 2023-03-17 22:15:25 +01:00
Lag 019399952f Better subtitle decoding :) 2023-03-17 16:23:03 +01:00
Lag cc99899cf1 Merge remote-tracking branch 'origin/master' 2023-03-17 16:07:33 +01:00
Lag 8fff809b79 Revert ffmpeg as it causes issues with subtitles :( 2023-03-17 16:07:28 +01:00
recloudstream[bot] 67318a62a3 chore(locales): fix locale issues 2023-03-17 15:04:00 +00:00
Hosted Weblate 288c5ffa39 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (German)

Currently translated at 100.0% (610 of 610 strings)

Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-03-17 16:03:40 +01:00
Lag 8ebf5185a3 Add ffmpeg audio decoding 2023-03-17 15:46:11 +01:00
Cloudburst 7bfcf25df4 add a way to autofix weblate's issue with @string 2023-03-14 18:50:13 +00:00
Lag 2d7126d71f Fix for fix for translations 2023-03-14 13:12:34 +01:00
Lag 40a4f319b6 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app/src/main/res/values-uk/strings.xml
2023-03-14 13:01:08 +01:00
Lag 19dc1a2456 Un-bruh-momented some translations 2023-03-14 12:59:32 +01:00
Cloudburst ac1012bcb8
Merge pull request #420 from recloudstream/weblate-guh 2023-03-13 18:32:15 +01:00
Cloudburst ec3950ed4f Merge branch 'master' of https://hosted.weblate.org/git/cloudstream/app 2023-03-13 18:18:13 +01:00
Hosted Weblate 3e2b0f2a17 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 74.0% (452 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Added translation using Weblate (Malay)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 99.1% (605 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Frank Gerritsen Mulkes <frankgmwerk@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Samuel Gadiel <samuelgadiel@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: TZVS <akyasan@tuta.io>
Co-authored-by: Tang Yin <bingyuanshiye@126.com>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-03-13 18:18:01 +01:00
LikDev-256 29174dbb30
Feat: fix Streamsb (#417)
* Fix Streamsb

* feat(StreamSB) stream break: support audiotracks

* Revert "feat(StreamSB) stream break: support audiotracks"

This reverts commit 078caf9f88.

* Feat: fix Streamsb

They normally update source numbers like 50, 51 but instead of 52 they totally dumped everything and just flipped the number into 15
2023-03-13 16:11:35 +00:00
Lag 7b47f93190 Merge remote-tracking branch 'origin/master' 2023-03-10 21:33:27 +01:00
Lag 13ee8e21d0 Semi-unfucked VLC on A13+ 2023-03-10 21:33:13 +01:00
recloudstream[bot] 3a5d872545 update list of locales 2023-03-10 20:01:20 +00:00
Hosted Weblate fab55d82c4 Translated using Weblate (Portuguese)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 74.0% (452 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Added translation using Weblate (Malay)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 99.1% (605 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Frank Gerritsen Mulkes <frankgmwerk@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Samuel Gadiel <samuelgadiel@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: TZVS <akyasan@tuta.io>
Co-authored-by: Tang Yin <bingyuanshiye@126.com>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-03-10 21:01:04 +01:00
Hosted Weblate 8b2881f5f6
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Dutch)

Currently translated at 74.0% (452 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Added translation using Weblate (Malay)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 99.1% (605 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (English)

Currently translated at 100.0% (610 of 610 strings)

Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Frank Gerritsen Mulkes <frankgmwerk@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Samuel Gadiel <samuelgadiel@gmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: TZVS <akyasan@tuta.io>
Co-authored-by: Tang Yin <bingyuanshiye@126.com>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-03-10 20:45:19 +01:00
PokerFace 37244ab0f7
Intertal Player: Added MPD support (#402)
* added isDash in ExtractorLink
2023-03-10 19:45:11 +00:00
Lag e85b31c35d Fixing rouge pixels in settings 2023-03-07 17:36:53 +01:00
Hosted Weblate 1eaa4620dc Translated using Weblate (qt (generated) (qt))
Currently translated at 54.5% (333 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (French)

Currently translated at 98.8% (603 of 610 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (German)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Russian)

Currently translated at 99.6% (608 of 610 strings)

Translated using Weblate (Portuguese)

Currently translated at 85.0% (519 of 610 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Vietnamese)

Currently translated at 96.8% (591 of 610 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (610 of 610 strings)

Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Duc Nguyen Tien <ducnt123@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Samuel Gadiel <samuelgadiel@gmail.com>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/qt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-03-03 18:16:40 +01:00
no-commit 76545f55c3 Standardized some home screen padding and made subtitle delay persistent. Fixes #405 2023-03-03 17:45:26 +01:00
Stormunblessed f0515c4dc9
Support qualities for Dailymotion (#407)
* Dailymotion qualities
2023-03-03 09:24:02 +00:00
no-commit ab324b93e8 Small fixes to Intents and Subscriptions 2023-02-28 01:19:59 +01:00
Stormunblessed d6df24eff2
Fixes on filesim and added filemoon, ztreamhub (#397)
* fix fastream, tomatomatela, and added okrulink

* forgot this

* sendvid extractor

* sendvid extractor

* fixes

* Filesim fix, added filemoon and ztreamhub
2023-02-27 20:05:42 +00:00
Hosted Weblate e5834d485b Translated using Weblate (German)
Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (610 of 610 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Portuguese)

Currently translated at 81.0% (493 of 608 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.5% (605 of 608 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (608 of 608 strings)

Translated using Weblate (Polish)

Currently translated at 97.3% (592 of 608 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Japanese)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (qt (generated) (qt))

Currently translated at 50.4% (304 of 602 strings)

Translated using Weblate (Slovak)

Currently translated at 31.7% (191 of 602 strings)

Translated using Weblate (Portuguese)

Currently translated at 76.9% (463 of 602 strings)

Translated using Weblate (Somali)

Currently translated at 94.3% (568 of 602 strings)

Translated using Weblate (Somali)

Currently translated at 94.3% (568 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Esperanto)

Currently translated at 27.5% (166 of 602 strings)

Translated using Weblate (Esperanto)

Currently translated at 27.5% (166 of 602 strings)

Translated using Weblate (Persian)

Currently translated at 20.0% (121 of 602 strings)

Translated using Weblate (Hungarian)

Currently translated at 55.6% (335 of 602 strings)

Translated using Weblate (German)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Russian)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Kannada)

Currently translated at 35.2% (212 of 602 strings)

Translated using Weblate (Urdu)

Currently translated at 72.2% (435 of 602 strings)

Translated using Weblate (Tamil)

Currently translated at 18.2% (110 of 602 strings)

Translated using Weblate (Tamil)

Currently translated at 18.2% (110 of 602 strings)

Translated using Weblate (Hebrew)

Currently translated at 97.1% (585 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 94.1% (567 of 602 strings)

Translated using Weblate (Vietnamese)

Currently translated at 96.8% (583 of 602 strings)

Translated using Weblate (Turkish)

Currently translated at 97.1% (585 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Polish)

Currently translated at 98.0% (590 of 602 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 88.3% (532 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Italian)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (French)

Currently translated at 97.3% (586 of 602 strings)

Translated using Weblate (Greek)

Currently translated at 97.0% (584 of 602 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (Bulgarian)

Currently translated at 94.5% (569 of 602 strings)

Translated using Weblate (Bulgarian)

Currently translated at 94.5% (569 of 602 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (602 of 602 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Japanese)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (qt (generated) (qt))

Currently translated at 50.4% (304 of 602 strings)

Translated using Weblate (Slovak)

Currently translated at 31.7% (191 of 602 strings)

Translated using Weblate (Portuguese)

Currently translated at 76.9% (463 of 602 strings)

Translated using Weblate (Somali)

Currently translated at 94.3% (568 of 602 strings)

Translated using Weblate (Somali)

Currently translated at 94.3% (568 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 44.5% (268 of 602 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Esperanto)

Currently translated at 27.5% (166 of 602 strings)

Translated using Weblate (Esperanto)

Currently translated at 27.5% (166 of 602 strings)

Translated using Weblate (Persian)

Currently translated at 20.0% (121 of 602 strings)

Translated using Weblate (Hungarian)

Currently translated at 55.6% (335 of 602 strings)

Translated using Weblate (German)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Russian)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Kannada)

Currently translated at 35.2% (212 of 602 strings)

Translated using Weblate (Kannada)

Currently translated at 35.2% (212 of 602 strings)

Translated using Weblate (Urdu)

Currently translated at 72.2% (435 of 602 strings)

Translated using Weblate (Tamil)

Currently translated at 18.2% (110 of 602 strings)

Translated using Weblate (Tamil)

Currently translated at 18.2% (110 of 602 strings)

Translated using Weblate (Hebrew)

Currently translated at 97.1% (585 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Bengali)

Currently translated at 38.7% (233 of 602 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 94.1% (567 of 602 strings)

Translated using Weblate (Vietnamese)

Currently translated at 96.8% (583 of 602 strings)

Translated using Weblate (Turkish)

Currently translated at 97.1% (585 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Tagalog)

Currently translated at 56.1% (338 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Swedish)

Currently translated at 74.9% (451 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Romanian)

Currently translated at 73.0% (440 of 602 strings)

Translated using Weblate (Polish)

Currently translated at 98.0% (590 of 602 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 88.3% (532 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Dutch)

Currently translated at 75.0% (452 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Malayalam)

Currently translated at 37.2% (224 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Macedonian)

Currently translated at 48.6% (293 of 602 strings)

Translated using Weblate (Italian)

Currently translated at 99.1% (597 of 602 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (Hindi)

Currently translated at 37.7% (227 of 602 strings)

Translated using Weblate (French)

Currently translated at 97.3% (586 of 602 strings)

Translated using Weblate (Greek)

Currently translated at 97.0% (584 of 602 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 77.4% (466 of 602 strings)

Translated using Weblate (Bulgarian)

Currently translated at 94.5% (569 of 602 strings)

Translated using Weblate (Bulgarian)

Currently translated at 94.5% (569 of 602 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (602 of 602 strings)

Co-authored-by: Aitor Salaberria <trslbrr@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Geovani Amaral <geovani.af4@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: MedRAM <mohammad7ram@users.noreply.hosted.weblate.org>
Co-authored-by: Prathap Rathod <prathap0144@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sandyran <sandyran@protonmail.com>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Translator-3000 <weblate.m1d0h@8shield.net>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bp/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/eo/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/he/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/qt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/so/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ta/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ur/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hant/
Translation: Cloudstream/App
2023-02-25 22:21:25 +01:00
Sarlay 6524eb220b
Added some extractors mirrors and added Vido Extractor (#393)
* Added some mirrors and fixed some extractors

* Fixed Vido extractor (for MesFilms and Wiflix)
2023-02-25 21:18:48 +00:00
Allen Baby 2926dc6c8e
Issue #376: Added new feature for separate watch quality on mobile data. (#391)
* Issue #376: Added new feature for separate watch quality on mobile data.
2023-02-24 18:51:03 +00:00
Hexated f722785a37
fixed Linkbox (#390) 2023-02-24 18:49:53 +00:00
Lag aeab423d29 Excluded the referer header when empty 2023-02-24 18:47:54 +01:00
recloudstream[bot] 1da6a92569 update list of locales 2023-02-21 18:07:04 +00:00
Cloudburst b2fa765a2d
Merge pull request #364 from recloudstream/weblate 2023-02-21 19:06:48 +01:00
Cloudburst bec0a2e7b9
Merge branch 'master' into weblate 2023-02-21 19:06:13 +01:00
Cloudburst 51137701f2
add proxy to raw.githubusercontent.com (#368) 2023-02-21 18:43:35 +01:00
Hosted Weblate 5f12d067f9
Translated using Weblate (Indonesian)
Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Slovak)

Currently translated at 31.7% (191 of 602 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (602 of 602 strings)

Translated using Weblate (German)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 44.8% (268 of 597 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 40.5% (242 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 34.5% (206 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 33.1% (198 of 597 strings)

Translated using Weblate (Kannada)

Currently translated at 35.5% (212 of 597 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 25.7% (154 of 597 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (German)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Romanian)

Currently translated at 73.7% (440 of 597 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (597 of 597 strings)

Translated using Weblate (Japanese)

Currently translated at 22.7% (134 of 589 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Japanese)

Currently translated at 17.8% (105 of 589 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.3% (585 of 589 strings)

Translated using Weblate (Japanese)

Currently translated at 16.6% (98 of 589 strings)

Translated using Weblate (Russian)

Currently translated at 99.6% (587 of 589 strings)

Translated using Weblate (Russian)

Currently translated at 99.4% (586 of 589 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 96.0% (566 of 589 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (German)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (French)

Currently translated at 99.3% (585 of 589 strings)

Added translation using Weblate (Japanese)

Translated using Weblate (Croatian)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Russian)

Currently translated at 98.9% (583 of 589 strings)

Translated using Weblate (French)

Currently translated at 98.6% (581 of 589 strings)

Translated using Weblate (French)

Currently translated at 96.6% (569 of 589 strings)

Translated using Weblate (Greek)

Currently translated at 98.9% (583 of 589 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (589 of 589 strings)

jsdelivr wrapper to githubusercontent

Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Andrey Zapolsky <zapoland@gmail.com>
Co-authored-by: Cliff Heraldo <123844876+clxf12@users.noreply.github.com>
Co-authored-by: Cliff Heraldo <cliffkbrt11@gmail.com>
Co-authored-by: Cliff Heraldo <clxf12@users.noreply.hosted.weblate.org>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Deleted User <noreply+57159@weblate.org>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Gabriel Cnudde <gabriel.cnudde59@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Juraj Liso <lisojuraj@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: MedRAM <mohammad7ram@users.noreply.hosted.weblate.org>
Co-authored-by: Piotr Strebski <strebski@gmail.com>
Co-authored-by: Prathap Rathod <prathap0144@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Translator-3000 <weblate.m1d0h@8shield.net>
Co-authored-by: abcabcc <xmmandxpp@outlook.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ja/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hant/
Translation: Cloudstream/App
2023-02-21 18:28:21 +01:00
no-commit 00a91ca5fb Added Subscriptions (pinged every ~6 hours) 2023-02-19 19:27:40 +01:00
LikDev-256 33aecfbba5
Fix Streamsb (#380) 2023-02-18 12:15:50 +00:00
no-commit 0185854682 Merge remote-tracking branch 'origin/master' 2023-02-17 23:06:16 +01:00
no-commit b4065b69be Added dropdown indicators
Solves #375
2023-02-17 23:05:11 +01:00
MhmdIbrahim1 b6ac155350
update VideoDownloadService (#377) 2023-02-17 21:42:20 +00:00
Lag aacd57cb5d Fixed scrolling up on bottom dialogs and removing stuff from AniList 2023-02-16 01:15:30 +01:00
Lag 3dd0fc6c8e add view_test 2023-02-15 22:09:08 +01:00
Lag 135f63afff Merge remote-tracking branch 'origin/master' 2023-02-15 21:41:28 +01:00
Lag 789cd14ef6 remove placeholder 2023-02-15 21:41:20 +01:00
recloudstream[bot] 9d0cce47a6 update list of locales 2023-02-15 20:40:50 +00:00
Lag 4a8ee55018 Added provider tests 2023-02-15 21:40:10 +01:00
Stormunblessed df6c395acb
Sendvid extractor (#365)
* fix fastream, tomatomatela, and added okrulink

* forgot this

* sendvid extractor

* sendvid extractor

* fixes
2023-02-14 15:11:20 +00:00
Cloudburst 1117271a71
[skip ci] português brasileiro 2023-02-10 15:16:58 +01:00
Cloudburst 7b11b9b585
fix wrong hebrew lang code 2023-02-09 20:27:37 +01:00
recloudstream[bot] 5c20b479e5 update list of locales 2023-02-09 19:25:34 +00:00
Hosted Weblate 0d2613d183 Translated using Weblate (qt (generated) (qt))
Currently translated at 51.4% (303 of 589 strings)

Translated using Weblate (Ukrainian)

Currently translated at 99.3% (585 of 589 strings)

Translated using Weblate (Persian)

Currently translated at 20.3% (120 of 589 strings)

Translated using Weblate (Russian)

Currently translated at 98.9% (583 of 589 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (589 of 589 strings)

Translated using Weblate (qt (generated) (qt))

Currently translated at 50.3% (293 of 582 strings)

Translated using Weblate (Persian)

Currently translated at 18.7% (109 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 99.1% (577 of 582 strings)

Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Soroush <skaveh1384@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: sina <cnababaie@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/qt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translation: Cloudstream/App
2023-02-09 20:25:19 +01:00
Cloudburst dd38556102
address issue #339
Co-authored-by: eightyy8 <64216434+eightyy8@users.noreply.github.com>
2023-02-09 20:25:00 +01:00
reduplicated 84493b7f3b mini fix 2023-02-09 01:46:07 +01:00
reduplicated 4596afee06 auto track anilist/mal 2023-02-09 01:32:48 +01:00
Sir Aguacata 3e2c2a5c86
Added a way for easy mal and anilist tracker (#359)
* Added a way for easy mal and anilist tracker, All credit gos to Hexated for helping me

* Made CodeFactor Fucking Happy

* prettified the getTracker method

* remove parenthesis

* fixed

---------

Co-authored-by: Blatzar <46196380+Blatzar@users.noreply.github.com>
Co-authored-by: reduplicated <110570621+reduplicated@users.noreply.github.com>
2023-02-08 23:58:15 +00:00
Terry Hanoman 6c646d65a8
Use user setting for seeking on Android TV (#342)
* Use user setting for seeking on Android TV

* Fixed left dpad seeking

* Added a Android TV section for seeking

* Fixed text

* Removed semi-colons
2023-02-08 15:46:39 +00:00
LagradOst 329966732f
increased app update buffer size 2023-02-07 16:01:14 +00:00
Hosted Weblate 19b2cae851 Translated using Weblate (English (en_MO))
Currently translated at 47.9% (279 of 582 strings)

Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en_MO/
Translation: Cloudstream/App
2023-02-07 12:53:13 +01:00
recloudstream[bot] 45eb9758e3 update list of locales 2023-02-07 11:52:20 +00:00
Cloudburst f6be6081dc use qt for monke language 2023-02-07 11:52:02 +00:00
recloudstream[bot] 80f22cea16 update list of locales 2023-02-07 10:21:26 +00:00
Cloudburst bf78fc95c2 use en-rMO 2023-02-07 10:21:07 +00:00
Cloudburst a148f347cd
[skip ci] issue action.yml 2023-02-07 11:15:00 +01:00
Cloudburst ff9942407b use language a better language code for the easter egg 2023-02-07 10:11:23 +00:00
Hosted Weblate 0ea624ff14 Translated using Weblate (Russian)
Currently translated at 98.9% (576 of 582 strings)

Translated using Weblate (Hebrew)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 98.7% (575 of 582 strings)

Translated using Weblate (Hebrew)

Currently translated at 87.4% (509 of 582 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 98.4% (573 of 582 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 98.4% (573 of 582 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (German)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 98.2% (572 of 582 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Bulgarian)

Currently translated at 97.2% (566 of 582 strings)

Translated using Weblate (English)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (German)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.9% (570 of 582 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 97.5% (568 of 582 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (582 of 582 strings)

Co-authored-by: Alexey <aleksejfedorov963@gmail.com>
Co-authored-by: Anarchydr <patrikpik879@gmail.com>
Co-authored-by: Cliff Heraldo <cliffkbrt11@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Fjuro <ifjuro@proton.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Joel Brink <joel.brink.handy@gmail.com>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Muhammet <zumruduanka0013@gmail.com>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: The Initiator <eithansten@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/en/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/he/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-02-07 11:05:37 +01:00
Cloudburst f939e4cff2 update langs to use native names fix #339 2023-02-07 10:04:27 +00:00
no-commit 2ff90c03ca Moved backup restore to IO thread. 2023-02-04 15:32:04 +01:00
no-commit 9988753432 Library and Light mode improvements. 2023-02-02 01:15:24 +01:00
LagradOst b0921161a3
Nicehttp version bump 2023-01-31 23:43:29 +01:00
Cloudburst 490381451b
[skip ci] label issues if provider mentioned 2023-01-31 10:57:11 +01:00
hexated b26a41bdaf fixed VidSrcExtractor 2023-01-31 09:13:46 +01:00
Hosted Weblate c7c5fa250e Translated using Weblate (Polish)
Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 96.5% (562 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 91.4% (532 of 582 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 90.3% (526 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 90.3% (526 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 88.3% (514 of 582 strings)

Translated using Weblate (Russian)

Currently translated at 87.9% (512 of 582 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (German)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (582 of 582 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (581 of 581 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (581 of 581 strings)

Co-authored-by: Aitor Salaberria <trslbrr@gmail.com>
Co-authored-by: Alex Georgiou <alexandrosgeorgiou35@gmail.com>
Co-authored-by: Cliff Heraldo <cliffkbrt11@gmail.com>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: JL Pilgram <twich_89@hotmail.it>
Co-authored-by: Julian <hello@apollo.moe>
Co-authored-by: NickSkier <nikita.vasiliev.02@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Skrripy <rozihrash.ya6w7@simplelogin.com>
Co-authored-by: Translator-3000 <weblate.m1d0h@8shield.net>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Co-authored-by: tuan041 <tuananh163025ttt@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translation: Cloudstream/App
2023-01-31 09:13:15 +01:00
Blatzar 6e9b1cb855 Made source dialog fullscreen and added some Extractors 2023-01-29 23:51:25 +01:00
Blatzar fd2648df45 made the checkSafeModeFile() crash-proof 2023-01-29 16:31:16 +01:00
Blatzar 9905618a47 Added safe mode file as a last resort 2023-01-29 16:15:28 +01:00
LagradOst 2771dcb612
update version code 2023-01-28 22:38:55 +00:00
LagradOst 3c82548c20
Library merge (#343) 2023-01-28 22:38:02 +00:00
recloudstream[bot] 9d11dc76a1 update list of locales 2023-01-28 18:43:31 +00:00
Hosted Weblate 2a1311673a Translated using Weblate (Russian)
Currently translated at 88.0% (499 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 86.7% (492 of 567 strings)

Translated using Weblate (Romanian)

Currently translated at 75.6% (429 of 567 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Russian)

Currently translated at 86.5% (491 of 567 strings)

Translated using Weblate (Vietnamese)

Currently translated at 99.2% (563 of 567 strings)

Translated using Weblate (Slovak)

Currently translated at 33.1% (188 of 567 strings)

Translated using Weblate (Somali)

Currently translated at 99.6% (565 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 84.1% (477 of 567 strings)

Translated using Weblate (German)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 84.1% (477 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 84.1% (477 of 567 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (567 of 567 strings)

Added translation using Weblate (Slovak)

Translated using Weblate (Vietnamese)

Currently translated at 99.4% (564 of 567 strings)

Co-authored-by: Alexey <aleksejfedorov963@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: John Doe <vj4ud1mc@sonofdavid.anonaddy.me>
Co-authored-by: Juraj Liso <lisojuraj@gmail.com>
Co-authored-by: Shafici Isxariifshe <mega12xhaphiee@gmail.com>
Co-authored-by: alex <hdhdhfhfbbffhhfhfjfjf@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Co-authored-by: tuan041 <30403510+tuan041@users.noreply.github.com>
Co-authored-by: tuan041 <tuananh163025ttt@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/so/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translation: Cloudstream/App
2023-01-28 19:43:15 +01:00
Blatzar 83d2e692e0 Made player_video_title_rez disappear if blank 2023-01-28 19:39:12 +01:00
Blatzar b2389bf14c Add padding in info & download to remove obtrusion by FAB 2023-01-28 19:00:10 +01:00
LiJu09 b2b16fccc5
[extractor] added ByteShare (#337)
* add byteshare extractor

* reformat code

* make it simple

* no regex
2023-01-27 23:44:00 +00:00
Blatzar 01f1edab3c webview crash fix 2023-01-26 00:34:55 +01:00
reduplicated 5050ff65c0 disabled crash reporting because yall keep crashing 2023-01-25 15:06:48 +01:00
Hosted Weblate de720983a6 Translated using Weblate (Russian)
Currently translated at 83.7% (475 of 567 strings)

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Portuguese)

Currently translated at 81.3% (461 of 567 strings)

Translated using Weblate (Somali)

Currently translated at 99.6% (565 of 567 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 46.7% (265 of 567 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 46.7% (265 of 567 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Esperanto)

Currently translated at 28.7% (163 of 567 strings)

Translated using Weblate (Persian)

Currently translated at 19.0% (108 of 567 strings)

Translated using Weblate (Hungarian)

Currently translated at 58.7% (333 of 567 strings)

Translated using Weblate (German)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 83.5% (474 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 83.5% (474 of 567 strings)

Translated using Weblate (Kannada)

Currently translated at 14.9% (85 of 567 strings)

Translated using Weblate (Urdu)

Currently translated at 76.3% (433 of 567 strings)

Translated using Weblate (Tamil)

Currently translated at 18.8% (107 of 567 strings)

Translated using Weblate (Hebrew)

Currently translated at 37.5% (213 of 567 strings)

Translated using Weblate (Bengali)

Currently translated at 40.7% (231 of 567 strings)

Translated using Weblate (Bengali)

Currently translated at 40.7% (231 of 567 strings)

Translated using Weblate (Bengali)

Currently translated at 40.7% (231 of 567 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 99.2% (563 of 567 strings)

Translated using Weblate (Vietnamese)

Currently translated at 87.6% (497 of 567 strings)

Translated using Weblate (Vietnamese)

Currently translated at 87.6% (497 of 567 strings)

Translated using Weblate (Vietnamese)

Currently translated at 87.6% (497 of 567 strings)

Translated using Weblate (Turkish)

Currently translated at 97.0% (550 of 567 strings)

Translated using Weblate (Tagalog)

Currently translated at 59.2% (336 of 567 strings)

Translated using Weblate (Tagalog)

Currently translated at 59.2% (336 of 567 strings)

Translated using Weblate (Tagalog)

Currently translated at 59.2% (336 of 567 strings)

Translated using Weblate (Swedish)

Currently translated at 79.1% (449 of 567 strings)

Translated using Weblate (Swedish)

Currently translated at 79.1% (449 of 567 strings)

Translated using Weblate (Swedish)

Currently translated at 79.1% (449 of 567 strings)

Translated using Weblate (Romanian)

Currently translated at 74.7% (424 of 567 strings)

Translated using Weblate (Romanian)

Currently translated at 74.7% (424 of 567 strings)

Translated using Weblate (Romanian)

Currently translated at 74.7% (424 of 567 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 93.4% (530 of 567 strings)

Translated using Weblate (Dutch)

Currently translated at 79.3% (450 of 567 strings)

Translated using Weblate (Dutch)

Currently translated at 79.3% (450 of 567 strings)

Translated using Weblate (Dutch)

Currently translated at 79.3% (450 of 567 strings)

Translated using Weblate (Malayalam)

Currently translated at 38.9% (221 of 567 strings)

Translated using Weblate (Malayalam)

Currently translated at 38.9% (221 of 567 strings)

Translated using Weblate (Malayalam)

Currently translated at 38.9% (221 of 567 strings)

Translated using Weblate (Macedonian)

Currently translated at 51.1% (290 of 567 strings)

Translated using Weblate (Macedonian)

Currently translated at 51.1% (290 of 567 strings)

Translated using Weblate (Macedonian)

Currently translated at 51.1% (290 of 567 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.6% (565 of 567 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Hindi)

Currently translated at 39.5% (224 of 567 strings)

Translated using Weblate (Hindi)

Currently translated at 39.5% (224 of 567 strings)

Translated using Weblate (Hindi)

Currently translated at 39.5% (224 of 567 strings)

Translated using Weblate (French)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Greek)

Currently translated at 99.8% (566 of 567 strings)

Translated using Weblate (Czech)

Currently translated at 72.6% (412 of 567 strings)

Translated using Weblate (Czech)

Currently translated at 72.6% (412 of 567 strings)

Translated using Weblate (Czech)

Currently translated at 72.6% (412 of 567 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 81.8% (464 of 567 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 81.8% (464 of 567 strings)

Translated using Weblate (bp (generated) (bp))

Currently translated at 81.8% (464 of 567 strings)

Translated using Weblate (Bulgarian)

Currently translated at 99.8% (566 of 567 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 83.4% (473 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 83.2% (472 of 567 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 81.6% (463 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 81.6% (463 of 567 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.6% (565 of 567 strings)

Translated using Weblate (Somali)

Currently translated at 99.6% (565 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 60.4% (343 of 567 strings)

Translated using Weblate (Vietnamese)

Currently translated at 87.6% (497 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 55.9% (317 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 55.9% (317 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 55.9% (317 of 567 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Russian)

Currently translated at 53.2% (302 of 567 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Turkish)

Currently translated at 97.0% (550 of 567 strings)

Translated using Weblate (Somali)

Currently translated at 69.6% (395 of 567 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (567 of 567 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (567 of 567 strings)

new string translations

Co-authored-by: Alexey <aleksejfedorov963@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Fikri Akbar <akbarfikri1221@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jonas Kahnwald <elcan.osmanov123@gmail.com>
Co-authored-by: Piotr Z <pzdanowiczp@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sandyran <sandyran@protonmail.com>
Co-authored-by: Sdarfeesh <Sdarfeesh@protonmail.com>
Co-authored-by: Shafici Isxariifshe <mega12xhaphiee@gmail.com>
Co-authored-by: Sina Sharifkazemi <negatics@gmail.com>
Co-authored-by: SleepyOwl <artem726artem@gmail.com>
Co-authored-by: Translator-3000 <weblate.m1d0h@8shield.net>
Co-authored-by: Walter H <walter75@gmail.com>
Co-authored-by: eightyy8 <oliver.kha@pm.me>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Co-authored-by: tuan041 <tuananh163025ttt@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ar/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bg/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/bp/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/cs/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/de/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/el/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/eo/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/es/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fa/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/fr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/he/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/hu/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/id/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/kn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/mk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ml/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/nn/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ro/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ru/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/so/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/sv/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ta/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tl/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/tr/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/ur/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/vi/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hant/
Translation: Cloudstream/App
2023-01-24 19:18:41 +01:00
Blatzar 0b4de81811 (hopefully) Fix home search and OpenSubtitles 2023-01-23 00:29:14 +01:00
635 changed files with 45942 additions and 14900 deletions

BIN
.github/downloads.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

BIN
.github/home.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

22
.github/locales.py vendored
View File

@ -1,13 +1,14 @@
import re
import glob
import requests
import lxml.etree as ET # builtin library doesn't preserve comments
SETTINGS_PATH = "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt"
START_MARKER = "/* begin language list */"
END_MARKER = "/* end language list */"
XML_NAME = "app/src/main/res/values-"
ISO_MAP_URL = "https://gist.githubusercontent.com/Josantonius/b455e315bc7f790d14b136d61d9ae469/raw"
ISO_MAP_URL = "https://raw.githubusercontent.com/haliaeetus/iso-639/master/data/iso_639-1.min.json"
INDENT = " "*4
iso_map = requests.get(ISO_MAP_URL, timeout=300).json()
@ -27,7 +28,8 @@ for lang in re.finditer(r'Triple\("(.*)", "(.*)", "(.*)"\)', rest):
for folder in glob.glob(f"{XML_NAME}*"):
iso = folder[len(XML_NAME):]
if iso not in languages.keys():
languages[iso] = ("", iso_map.get(iso.lower(),iso))
entry = iso_map.get(iso.lower(),{'nativeName':iso})
languages[iso] = ("", entry['nativeName'].split(',')[0])
# Create triples
triples = []
@ -44,4 +46,18 @@ open(SETTINGS_PATH, "w+",encoding='utf-8').write(
"\n" +
END_MARKER +
after_src
)
)
# Go through each values.xml file and fix escaped \@string
for file in glob.glob(f"{XML_NAME}*/strings.xml"):
try:
tree = ET.parse(file)
for child in tree.getroot():
if child.text.startswith("\\@string/"):
print(f"[{file}] fixing {child.attrib['name']}")
child.text = child.text.replace("\\@string/", "@string/")
with open(file, 'wb') as fp:
fp.write(b'<?xml version="1.0" encoding="utf-8"?>\n')
tree.write(fp, encoding="utf-8", method="xml", pretty_print=True, xml_declaration=False)
except ET.ParseError as ex:
print(f"[{file}] {ex}")

BIN
.github/player.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

BIN
.github/results.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

BIN
.github/search.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

View File

@ -19,23 +19,23 @@ jobs:
steps:
- name: Generate access token
id: generate_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
repository: "recloudstream/secrets"
- name: Generate access token (archive)
id: generate_archive_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
repository: "recloudstream/cloudstream-archive"
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
@ -56,7 +56,9 @@ jobs:
SIGNING_KEY_ALIAS: "key0"
SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
SIGNING_STORE_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
- uses: actions/checkout@v3
SIMKL_CLIENT_ID: ${{ secrets.SIMKL_CLIENT_ID }}
SIMKL_CLIENT_SECRET: ${{ secrets.SIMKL_CLIENT_SECRET }}
- uses: actions/checkout@v4
with:
repository: "recloudstream/cloudstream-archive"
token: ${{ steps.generate_archive_token.outputs.token }}

View File

@ -20,7 +20,7 @@ jobs:
steps:
- name: Generate access token
id: generate_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
@ -42,13 +42,14 @@ jobs:
cd $GITHUB_WORKSPACE/dokka/
rm -rf "./-cloudstream"
- name: Setup JDK 11
uses: actions/setup-java@v1
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
java-version: 11
java-version: 17
distribution: 'adopt'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
uses: android-actions/setup-android@v3
- name: Generate Dokka
run: |

View File

@ -10,11 +10,12 @@ jobs:
steps:
- name: Generate access token
id: generate_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
- name: Similarity analysis
id: similarity
uses: actions-cool/issues-similarity-analysis@v1
with:
token: ${{ steps.generate_token.outputs.token }}
@ -24,7 +25,19 @@ jobs:
### Your issue looks similar to these issues:
Please close if duplicate.
comment-body: '${index}. ${similarity} #${number}'
- uses: actions/checkout@v2
- name: Label if possible duplicate
if: steps.similarity.outputs.similar-issues-found =='true'
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate_token.outputs.token }}
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["possible duplicate"]
})
- uses: actions/checkout@v4
- name: Automatically close issues that dont follow the issue template
uses: lucasbento/auto-close-issues@v1.0.2
with:
@ -53,6 +66,18 @@ jobs:
Please do not report any provider bugs here. This repository does not contain any providers. Please find the appropriate repository and report your issue there or join the [discord](https://discord.gg/5Hus6fM).
Found provider name: `${{ steps.provider_check.outputs.name }}`
- name: Label if mentions provider
if: steps.provider_check.outputs.name != 'none'
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate_token.outputs.token }}
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["possible provider issue"]
})
- name: Add eyes reaction to all issues
uses: actions-cool/emoji-helper@v1.0.0
with:

View File

@ -18,16 +18,16 @@ jobs:
steps:
- name: Generate access token
id: generate_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
repository: "recloudstream/secrets"
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
@ -43,11 +43,14 @@ jobs:
echo "key_pwd=$KEY_PWD" >> $GITHUB_OUTPUT
- name: Run Gradle
run: |
./gradlew assemblePrerelease makeJar androidSourcesJar
./gradlew assemblePrerelease build androidSourcesJar
./gradlew makeJar # for classes.jar, has to be done after assemblePrerelease
env:
SIGNING_KEY_ALIAS: "key0"
SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
SIGNING_STORE_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
SIMKL_CLIENT_ID: ${{ secrets.SIMKL_CLIENT_ID }}
SIMKL_CLIENT_SECRET: ${{ secrets.SIMKL_CLIENT_SECRET }}
- name: Create pre-release
uses: "marvinpinto/action-automatic-releases@latest"
with:

View File

@ -6,18 +6,18 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run Gradle
run: ./gradlew assemblePrereleaseDebug
- name: Upload Artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: pull-request-build
path: "app/build/outputs/apk/prerelease/debug/*.apk"

View File

@ -1,4 +1,4 @@
name: Update locale lists
name: Fix locale issues
on:
workflow_dispatch:
@ -9,7 +9,7 @@ on:
- master
concurrency:
group: "locale-list"
group: "locale"
cancel-in-progress: true
jobs:
@ -18,14 +18,17 @@ jobs:
steps:
- name: Generate access token
id: generate_token
uses: tibdex/github-app-token@v1
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_KEY }}
repository: "recloudstream/cloudstream"
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Install dependencies
run: |
pip3 install lxml
- name: Edit files
run: |
python3 .github/locales.py
@ -35,5 +38,5 @@ jobs:
git config --local user.name "recloudstream[bot]"
git add .
# "echo" returns true so the build succeeds, even if no changed files
git commit -m 'update list of locales' || echo
git commit -m 'chore(locales): fix locale issues' || echo
git push

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
<bytecodeTargetLevel target="17" />
</component>
</project>
</project>

View File

@ -4,17 +4,16 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="true" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="11" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/library" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

View File

@ -9,15 +9,11 @@
+ **AdFree**, No ads whatsoever
+ No tracking/analytics
+ Bookmarks
+ Download and stream movies, tv-shows and anime
+ Phone and TV support
+ Chromecast
### Screenshots:
<img src="./.github/home.jpg" height="400"/><img src="./.github/search.jpg" height="400"/><img src="./.github/downloads.jpg" height="400"/><img src="./.github/results.jpg" height="400"/>
<img src="./.github/player.jpg" height="200"/>
+ Extension system for personal customization
### Supported languages:
<a href="https://hosted.weblate.org/engage/cloudstream/">
<img src="https://hosted.weblate.org/widgets/cloudstream/-/app/multi-auto.svg" alt="Translation status" />
</a>
</a>

6
app/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
# Set this to the minimum version your project supports.
cmake_minimum_required(VERSION 3.18)
project(CrashHandler)
find_library(log-lib log)
add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
target_link_libraries(native-lib ${log-lib})

View File

@ -1,25 +1,27 @@
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.ByteArrayOutputStream
import java.net.URL
plugins {
id("com.android.application")
id("com.google.devtools.ksp")
id("kotlin-android")
id("kotlin-kapt")
id("kotlin-android-extensions")
id("org.jetbrains.dokka")
}
val tmpFilePath = System.getProperty("user.home") + "/work/_temp/keystore/"
val prereleaseStoreFile: File? = File(tmpFilePath).listFiles()?.first()
var isLibraryDebug = false
fun String.execute() = ByteArrayOutputStream().use { baot ->
if (project.exec {
workingDir = projectDir
commandLine = this@execute.split(Regex("\\s"))
standardOutput = baot
}.exitValue == 0)
}.exitValue == 0)
String(baot.toByteArray()).trim()
else null
}
@ -28,6 +30,18 @@ android {
testOptions {
unitTests.isReturnDefaultValues = true
}
viewBinding {
enable = true
}
/* disable this for now
externalNativeBuild {
cmake {
path("CMakeLists.txt")
}
}*/
signingConfigs {
create("prerelease") {
if (prereleaseStoreFile != null) {
@ -39,33 +53,44 @@ android {
}
}
compileSdk = 33
buildToolsVersion = "30.0.3"
compileSdk = 34
buildToolsVersion = "34.0.0"
defaultConfig {
applicationId = "com.lagradost.cloudstream3"
minSdk = 21
targetSdk = 33
versionCode = 55
versionName = "3.4.0"
targetSdk = 33 /* Android 14 is Fu*ked
^ https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading*/
versionCode = 63
versionName = "4.3.2"
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")
resValue("string", "commit_hash", "git rev-parse --short HEAD".execute() ?: "")
resValue("bool", "is_prerelease", "false")
// Reads local.properties
val localProperties = gradleLocalProperties(rootDir)
buildConfigField(
"long",
"BUILD_DATE",
"${System.currentTimeMillis()}"
)
buildConfigField(
"String",
"BUILDDATE",
"new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm\").format(new java.util.Date(" + System.currentTimeMillis() + "L));"
"SIMKL_CLIENT_ID",
"\"" + (System.getenv("SIMKL_CLIENT_ID") ?: localProperties["simkl.id"]) + "\""
)
buildConfigField(
"String",
"SIMKL_CLIENT_SECRET",
"\"" + (System.getenv("SIMKL_CLIENT_SECRET") ?: localProperties["simkl.secret"]) + "\""
)
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
kapt {
includeCompileClasspath = true
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
arg("exportSchema", "true")
}
}
@ -74,14 +99,22 @@ android {
isDebuggable = false
isMinifyEnabled = false
isShrinkResources = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isLibraryDebug = true
isDebuggable = true
applicationIdSuffix = ".debug"
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
flavorDimensions.add("state")
productFlavors {
create("stable") {
@ -98,20 +131,22 @@ android {
versionCode = (System.currentTimeMillis() / 60000).toInt()
}
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjvm-default=compatibility")
}
lint {
abortOnError = false
checkReleaseBuilds = false
}
buildFeatures {
buildConfig = true
}
namespace = "com.lagradost.cloudstream3"
}
@ -120,119 +155,124 @@ repositories {
}
dependencies {
implementation("com.google.android.mediahome:video:1.0.0")
implementation("androidx.test.ext:junit-ktx:1.1.3")
testImplementation("org.json:json:20180813")
implementation("androidx.core:core-ktx:1.8.0")
implementation("androidx.appcompat:appcompat:1.4.2") // need target 32 for 1.5.0
// dont change this to 1.6.0 it looks ugly af
implementation("com.google.android.material:material:1.5.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.5.1")
implementation("androidx.navigation:navigation-ui-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
// Testing
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
testImplementation("org.json:json:20240303")
androidTestImplementation("androidx.test:core")
implementation("androidx.test.ext:junit-ktx:1.1.5")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
//implementation("io.karn:khttp-android:0.1.2") //okhttp instead
// implementation("org.jsoup:jsoup:1.13.1")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1")
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("com.github.bumptech.glide:glide:4.13.1")
kapt("com.github.bumptech.glide:compiler:4.13.1")
implementation("com.github.bumptech.glide:okhttp3-integration:4.13.0")
// Android Core & Lifecycle
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
// Design & UI
implementation("jp.wasabeef:glide-transformations:4.3.0")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
// implementation("androidx.leanback:leanback-paging:1.1.0-alpha09")
// Glide Module
ksp("com.github.bumptech.glide:ksp:4.16.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0")
// Exoplayer
implementation("com.google.android.exoplayer:exoplayer:2.18.2")
implementation("com.google.android.exoplayer:extension-cast:2.18.2")
implementation("com.google.android.exoplayer:extension-mediasession:2.18.2")
implementation("com.google.android.exoplayer:extension-okhttp:2.18.2")
// For KSP -> Official Annotation Processors are Not Yet Supported for KSP
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
implementation("com.google.guava:guava:32.1.3-android")
implementation("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
//implementation("com.google.android.exoplayer:extension-leanback:2.14.0")
// Media 3 (ExoPlayer)
implementation("androidx.media3:media3-ui:1.1.1")
implementation("androidx.media3:media3-cast:1.1.1")
implementation("androidx.media3:media3-common:1.1.1")
implementation("androidx.media3:media3-session:1.1.1")
implementation("androidx.media3:media3-exoplayer:1.1.1")
implementation("com.google.android.mediahome:video:1.0.0")
implementation("androidx.media3:media3-exoplayer-hls:1.1.1")
implementation("androidx.media3:media3-exoplayer-dash:1.1.1")
implementation("androidx.media3:media3-datasource-okhttp:1.1.1")
// Bug reports
implementation("ch.acra:acra-core:5.8.4")
implementation("ch.acra:acra-toast:5.8.4")
// PlayBack
implementation("com.jaredrummler:colorpicker:1.1.0") // Subtitle Color Picker
implementation("com.github.recloudstream:media-ffmpeg:1.1.0") // Custom FF-MPEG Lib for Audio Codecs
implementation("com.github.TeamNewPipe.NewPipeExtractor:NewPipeExtractor:6dc25f7b97") /* For Trailers
^ Update to Latest Commits if Trailers Misbehave, github.com/TeamNewPipe/NewPipeExtractor/commits/dev */
implementation("com.github.albfernandez:juniversalchardet:2.4.0") // Subtitle Decoding
compileOnly("com.google.auto.service:auto-service-annotations:1.0")
//either for java sources:
annotationProcessor("com.google.auto.service:auto-service:1.0")
//or for kotlin sources (requires kapt gradle plugin):
kapt("com.google.auto.service:auto-service:1.0")
// subtitle color picker
implementation("com.jaredrummler:colorpicker:1.1.0")
//run JS
// do not upgrade to 1.7.14, since in 1.7.14 Rhino uses the `SourceVersion` class, which is not
// available on Android (even when using desugaring), and `NoClassDefFoundError` is thrown
implementation("org.mozilla:rhino:1.7.13")
// TorrentStream
//implementation("com.github.TorrentStream:TorrentStream-Android:2.7.0")
// Downloading
implementation("androidx.work:work-runtime:2.7.1")
implementation("androidx.work:work-runtime-ktx:2.7.1")
// Networking
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
// implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1")
implementation("com.github.Blatzar:NiceHttp:0.4.1")
// To fix SSL fuckery on android 9
implementation("org.conscrypt:conscrypt-android:2.2.1")
// Util to skip the URI file fuckery 🙏
implementation("com.github.tachiyomiorg:unifile:17bec43")
// API because cba maintaining it myself
implementation("com.uwetrottmann.tmdb2:tmdb-java:2.6.0")
implementation("com.github.discord:OverlappingPanels:0.1.3")
// debugImplementation because LeakCanary should only run in debug builds.
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
// for shimmer when loading
implementation("com.facebook.shimmer:shimmer:0.5.0")
// Crash Reports (AcraApplication.kt)
implementation("ch.acra:acra-core:5.11.3")
implementation("ch.acra:acra-toast:5.11.3")
// UI Stuff
implementation("com.facebook.shimmer:shimmer:0.5.0") // Shimmering Effect (Loading Skeleton)
implementation("androidx.palette:palette-ktx:1.0.0") // Palette For Images -> Colors
implementation("androidx.tvprovider:tvprovider:1.0.0")
implementation("com.github.discord:OverlappingPanels:0.1.5") // Gestures
implementation ("androidx.biometric:biometric:1.2.0-alpha05") // Fingerprint Authentication
implementation("com.github.rubensousa:previewseekbar-media3:1.1.1.0") // SeekBar Preview
// used for subtitle decoding https://github.com/albfernandez/juniversalchardet
implementation("com.github.albfernandez:juniversalchardet:2.4.0")
// Extensions & Other Libs
implementation("org.mozilla:rhino:1.7.13") /* run JavaScript
^ Don't Bump RhinoJS to 1.7.14,`NoClassDefFoundError` Occurs and Trailers won't play (even with Desugaring)
NewPipeExtractor Issue */
implementation("me.xdrop:fuzzywuzzy:1.4.0") // Library/Ext Searching with Levenshtein Distance
implementation("com.github.LagradOst:SafeFile:0.0.6") // To Prevent the URI File Fu*kery
implementation("org.conscrypt:conscrypt-android:2.5.2") // To Fix SSL Fu*kery on Android 9
implementation("com.uwetrottmann.tmdb2:tmdb-java:2.10.0") // TMDB API v3 Wrapper Made with RetroFit
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1") /* JSON Parser
^ Don't Bump Jackson above 2.13.1 , Crashes on Android TV's and FireSticks that have Min API
Level 25 or Less. */
// slow af yt
//implementation("com.github.HaarigerHarald:android-youtubeExtractor:master-SNAPSHOT")
// Downloading & Networking
implementation("androidx.work:work-runtime:2.9.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("com.github.Blatzar:NiceHttp:0.4.11") // HTTP Lib
// newpipe yt taken from https://github.com/TeamNewPipe/NewPipe/blob/dev/app/build.gradle#L190
implementation("com.github.TeamNewPipe:NewPipeExtractor:9ffdd0948b2ecd82655f5ff2a3e127b2b7695d5b")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
// Library/extensions searching with Levenshtein distance
implementation("me.xdrop:fuzzywuzzy:1.4.0")
implementation(project(":library") {
this.extra.set("isDebug", isLibraryDebug)
})
}
tasks.register("androidSourcesJar", Jar::class) {
tasks.register<Jar>("androidSourcesJar") {
archiveClassifier.set("sources")
from(android.sourceSets.getByName("main").java.srcDirs) //full sources
from(android.sourceSets.getByName("main").java.srcDirs) // Full Sources
}
// this is used by the gradlew plugin
tasks.register("makeJar", Copy::class) {
from("build/intermediates/compile_app_classes_jar/prereleaseDebug")
into("build")
include("classes.jar")
dependsOn("build")
tasks.register<Copy>("copyJar") {
from(
"build/intermediates/compile_app_classes_jar/prereleaseDebug",
"../library/build/libs"
)
into("build/app-classes")
include("classes.jar", "library-jvm*.jar")
// Remove the version
rename("library-jvm.*.jar", "library-jvm.jar")
}
// Merge the app classes and the library classes into classes.jar
tasks.register<Jar>("makeJar") {
dependsOn(tasks.getByName("copyJar"))
from(
zipTree("build/app-classes/classes.jar"),
zipTree("build/app-classes/library-jvm.jar")
)
destinationDirectory.set(layout.buildDirectory)
archivesName = "classes"
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
}
}
tasks.withType<DokkaTask>().configureEach {
@ -245,9 +285,10 @@ tasks.withType<DokkaTask>().configureEach {
// URL showing where the source code can be accessed through the web browser
remoteUrl.set(URL("https://github.com/recloudstream/cloudstream/tree/master/app/src/main/java"))
// Suffix which is used to append the line number to the URL. Use #L for GitHub
remoteLineSuffix.set("#L")
}
}
}
}
}

View File

@ -1,155 +1,57 @@
package com.lagradost.cloudstream3
import android.app.Activity
import android.os.Bundle
import android.os.PersistableBundle
import android.view.LayoutInflater
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.Qualities
import androidx.viewbinding.ViewBinding
import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
import com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding
import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding
import com.lagradost.cloudstream3.databinding.FragmentLibraryTvBinding
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
import com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding
import com.lagradost.cloudstream3.databinding.FragmentResultBinding
import com.lagradost.cloudstream3.databinding.FragmentResultTvBinding
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
import com.lagradost.cloudstream3.databinding.HomepageParentBinding
import com.lagradost.cloudstream3.databinding.HomepageParentEmulatorBinding
import com.lagradost.cloudstream3.databinding.HomepageParentTvBinding
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutTvBinding
import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
import com.lagradost.cloudstream3.databinding.TrailerCustomLayoutBinding
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.TestingUtils
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class TestApplication : Activity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
}
}
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
//@Test
//fun useAppContext() {
// // Context of the app under test.
// val appContext = InstrumentationRegistry.getInstrumentation().targetContext
// assertEquals("com.lagradost.cloudstream3", appContext.packageName)
//}
private fun getAllProviders(): List<MainAPI> {
return APIHolder.allProviders //.filter { !it.usesWebView }
}
private suspend fun loadLinks(api: MainAPI, url: String?): Boolean {
Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
if (url == null) return true
var linksLoaded = 0
try {
val success = api.loadLinks(url, false, {}) { link ->
Assert.assertTrue(
"Api ${api.name} returns link with invalid Quality",
Qualities.values().map { it.value }.contains(link.quality)
)
Assert.assertTrue(
"Api ${api.name} returns link with invalid url ${link.url}",
link.url.length > 4
)
linksLoaded++
}
if (success) {
return linksLoaded > 0
}
Assert.assertTrue("Api ${api.name} has returns false on .loadLinks", success)
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .loadLinks")
}
logError(e)
}
return true
}
private suspend fun testSingleProviderApi(api: MainAPI): Boolean {
val searchQueries = listOf("over", "iron", "guy")
var correctResponses = 0
var searchResult: List<SearchResponse>? = null
for (query in searchQueries) {
val response = try {
api.search(query)
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .search")
}
logError(e)
null
}
if (!response.isNullOrEmpty()) {
correctResponses++
if (searchResult == null) {
searchResult = response
}
}
}
if (correctResponses == 0 || searchResult == null) {
System.err.println("Api ${api.name} did not return any valid search responses")
return false
}
try {
var validResults = false
for (result in searchResult) {
Assert.assertEquals(
"Invalid apiName on response on ${api.name}",
result.apiName,
api.name
)
val load = api.load(result.url) ?: continue
Assert.assertEquals(
"Invalid apiName on load on ${api.name}",
load.apiName,
result.apiName
)
Assert.assertTrue(
"Api ${api.name} on load does not contain any of the supportedTypes",
api.supportedTypes.contains(load.type)
)
when (load) {
is AnimeLoadResponse -> {
val gotNoEpisodes =
load.episodes.keys.isEmpty() || load.episodes.keys.any { load.episodes[it].isNullOrEmpty() }
if (gotNoEpisodes) {
println("Api ${api.name} got no episodes on ${load.url}")
continue
}
val url = (load.episodes[load.episodes.keys.first()])?.first()?.data
validResults = loadLinks(api, url)
if (!validResults) continue
}
is MovieLoadResponse -> {
val gotNoEpisodes = load.dataUrl.isBlank()
if (gotNoEpisodes) {
println("Api ${api.name} got no movie on ${load.url}")
continue
}
validResults = loadLinks(api, load.dataUrl)
if (!validResults) continue
}
is TvSeriesLoadResponse -> {
val gotNoEpisodes = load.episodes.isEmpty()
if (gotNoEpisodes) {
println("Api ${api.name} got no episodes on ${load.url}")
continue
}
validResults = loadLinks(api, load.episodes.first().data)
if (!validResults) continue
}
}
break
}
if (!validResults) {
System.err.println("Api ${api.name} did not load on any")
}
return validResults
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .load")
}
logError(e)
return false
}
private fun getAllProviders(): Array<MainAPI> {
println("Providers: ${APIHolder.allProviders.size}")
return APIHolder.allProviders.toTypedArray() //.filter { !it.usesWebView }
}
@Test
@ -158,7 +60,78 @@ class ExampleInstrumentedTest {
println("Done providersExist")
}
@Throws
private inline fun <reified T : ViewBinding> testAllLayouts(
activity: Activity,
vararg layouts: Int
) {
val bind = T::class.java.methods.first { it.name == "bind" }
val inflater = LayoutInflater.from(activity)
for (layout in layouts) {
val root = inflater.inflate(layout, null, false)
bind.invoke(null, root)
}
}
@Test
@Throws
fun layoutTest() {
ActivityScenario.launch(MainActivity::class.java).use { scenario ->
scenario.onActivity { activity: MainActivity ->
// FragmentHomeHeadBinding and FragmentHomeHeadTvBinding CANT be the same
//testAllLayouts<FragmentHomeHeadBinding>(activity, R.layout.fragment_home_head, R.layout.fragment_home_head_tv)
//testAllLayouts<FragmentHomeHeadTvBinding>(activity, R.layout.fragment_home_head, R.layout.fragment_home_head_tv)
// main cant be tested
// testAllLayouts<ActivityMainTvBinding>(activity,R.layout.activity_main, R.layout.activity_main_tv)
// testAllLayouts<ActivityMainBinding>(activity,R.layout.activity_main, R.layout.activity_main_tv)
//testAllLayouts<ActivityMainBinding>(activity, R.layout.activity_main_tv)
testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
// testAllLayouts<FragmentResultBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
// testAllLayouts<FragmentResultTvBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
testAllLayouts<TrailerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
testAllLayouts<FragmentHomeBinding>(activity, R.layout.fragment_home_tv, R.layout.fragment_home)
testAllLayouts<FragmentHomeTvBinding>(activity, R.layout.fragment_home_tv, R.layout.fragment_home)
testAllLayouts<FragmentSearchBinding>(activity, R.layout.fragment_search_tv, R.layout.fragment_search)
testAllLayouts<FragmentSearchTvBinding>(activity, R.layout.fragment_search_tv, R.layout.fragment_search)
testAllLayouts<HomeResultGridBinding>(activity, R.layout.home_result_grid_expanded, R.layout.home_result_grid)
//testAllLayouts<HomeResultGridExpandedBinding>(activity, R.layout.home_result_grid_expanded, R.layout.home_result_grid) ??? fails ???
testAllLayouts<SearchResultGridExpandedBinding>(activity, R.layout.search_result_grid, R.layout.search_result_grid_expanded)
testAllLayouts<SearchResultGridBinding>(activity, R.layout.search_result_grid, R.layout.search_result_grid_expanded)
// testAllLayouts<HomeScrollViewBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
// testAllLayouts<HomeScrollViewTvBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
testAllLayouts<HomepageParentTvBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
testAllLayouts<HomepageParentEmulatorBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
testAllLayouts<HomepageParentBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
testAllLayouts<FragmentLibraryTvBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
testAllLayouts<FragmentLibraryBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
}
}
}
@Test
@Throws(AssertionError::class)
fun providerCorrectData() {
val isoNames = SubtitleHelper.languages.map { it.ISO_639_1 }
Assert.assertFalse("ISO does not contain any languages", isoNames.isNullOrEmpty())
@ -180,68 +153,21 @@ class ExampleInstrumentedTest {
@Test
fun providerCorrectHomepage() {
runBlocking {
getAllProviders().amap { api ->
if (api.hasMainPage) {
try {
val f = api.mainPage.first()
val homepage =
api.getMainPage(1, MainPageRequest(f.name, f.data, f.horizontalImages))
when {
homepage == null -> {
System.err.println("Homepage provider ${api.name} did not correctly load homepage!")
}
homepage.items.isEmpty() -> {
System.err.println("Homepage provider ${api.name} does not contain any items!")
}
homepage.items.any { it.list.isEmpty() } -> {
System.err.println("Homepage provider ${api.name} does not have any items on result!")
}
}
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider marked as hasMainPage, while in reality is has not been implemented")
}
logError(e)
}
}
getAllProviders().toList().amap { api ->
TestingUtils.testHomepage(api, ::println)
}
}
println("Done providerCorrectHomepage")
}
// @Test
// fun testSingleProvider() {
// testSingleProviderApi(ThenosProvider())
// }
@Test
fun providerCorrect() {
fun testAllProvidersCorrect() {
runBlocking {
val invalidProvider = ArrayList<Pair<MainAPI, Exception?>>()
val providers = getAllProviders()
providers.amap { api ->
try {
println("Trying $api")
if (testSingleProviderApi(api)) {
println("Success $api")
} else {
System.err.println("Error $api")
invalidProvider.add(Pair(api, null))
}
} catch (e: Exception) {
logError(e)
invalidProvider.add(Pair(api, e))
}
}
if (invalidProvider.isEmpty()) {
println("No Invalid providers! :D")
} else {
println("Invalid providers are: ")
for (provider in invalidProvider) {
println("${provider.first}")
}
}
TestingUtils.getDeferredProviderTests(
this,
getAllProviders(),
::println
) { _, _ -> }
}
println("Done providerCorrect")
}
}

View File

@ -6,7 +6,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <!-- unless you only use cs3 as a player for downloaded stuff, you need this -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Downloads -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Downloads on low api devices -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- Plugin API -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" /> <!-- Plugin API -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- some dependency needs this -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- Used for player vertical slide -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <!-- Used for app update -->
@ -14,8 +14,14 @@
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <!-- Used for Android TV watch next -->
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" /> <!-- Used for updates without prompt -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Used for update service -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<!-- Required for getting arbitrary Aniyomi packages -->
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<!-- <permission android:name="android.permission.QUERY_ALL_PACKAGES" /> &lt;!&ndash; Used for getting if vlc is installed &ndash;&gt; -->
<!-- Fixes android tv fuckery -->
<uses-feature
android:name="android.hardware.touchscreen"
@ -35,9 +41,11 @@
<application
android:name=".AcraApplication"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:appCategory="video"
android:banner="@mipmap/ic_banner"
android:fullBackupContent="@xml/backup_descriptor"
android:dataExtractionRules="@xml/data_extraction_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
@ -45,7 +53,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:targetApi="o">
tools:targetApi="tiramisu">
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
@ -61,7 +69,9 @@
android:exported="true"
android:resizeableActivity="true"
android:screenOrientation="userLandscape"
android:supportsPictureInPicture="true">
android:supportsPictureInPicture="true"
android:taskAffinity="com.lagradost.cloudstream3.downloadedplayer"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -92,11 +102,15 @@
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true">
<intent-filter android:exported="true">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<!-- cloudstreamplayer://encodedUrl?name=Dune -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="cloudstreamplayer" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -151,6 +165,21 @@
</intent-filter>
</activity>
<activity
android:name=".ui.account.AccountSelectActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:exported="true">
<intent-filter android:exported="true">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ui.EasterEggMonke"
android:exported="true" />
@ -158,13 +187,14 @@
<receiver
android:name=".receivers.VideoDownloadRestartReceiver"
android:enabled="false"
android:exported="true">
<intent-filter android:exported="true">
android:exported="false">
<intent-filter android:exported="false">
<action android:name="restart_service" />
</intent-filter>
</receiver>
<service
android:foregroundServiceType="dataSync"
android:name=".services.VideoDownloadService"
android:enabled="true"
android:exported="false" />
@ -174,6 +204,7 @@
android:exported="false" />
<service
android:foregroundServiceType="dataSync"
android:name=".utils.PackageInstallerService"
android:exported="false" />

View File

@ -0,0 +1,28 @@
#include <jni.h>
#include <csignal>
#include <android/log.h>
#define TAG "CloudStream Crash Handler"
volatile sig_atomic_t gSignalStatus = 0;
void handleNativeCrash(int signal) {
gSignalStatus = signal;
}
extern "C" JNIEXPORT void JNICALL
Java_com_lagradost_cloudstream3_NativeCrashHandler_initNativeCrashHandler(JNIEnv *env, jobject) {
#define REGISTER_SIGNAL(X) signal(X, handleNativeCrash);
REGISTER_SIGNAL(SIGSEGV)
#undef REGISTER_SIGNAL
}
//extern "C" JNIEXPORT void JNICALL
//Java_com_lagradost_cloudstream3_NativeCrashHandler_triggerNativeCrash(JNIEnv *env, jobject thiz) {
// int *p = nullptr;
// *p = 0;
//}
extern "C" JNIEXPORT int JNICALL
Java_com_lagradost_cloudstream3_NativeCrashHandler_getSignalStatus(JNIEnv *env, jobject) {
//__android_log_print(ANDROID_LOG_INFO, TAG, "Got signal status %d", gSignalStatus);
return gSignalStatus;
}

View File

@ -8,11 +8,12 @@ import android.content.Intent
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.google.auto.service.AutoService
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
import com.lagradost.cloudstream3.ui.settings.Globals.TV
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
import com.lagradost.cloudstream3.utils.DataStore.getKey
@ -32,27 +33,25 @@ import org.acra.sender.ReportSenderFactory
import java.io.File
import java.io.FileNotFoundException
import java.io.PrintStream
import java.lang.Exception
import java.lang.ref.WeakReference
import kotlin.concurrent.thread
import kotlin.system.exitProcess
class CustomReportSender : ReportSender {
// Sends all your crashes to google forms
override fun send(context: Context, errorContent: CrashReportData) {
println("Sending report")
val url =
"https://docs.google.com/forms/u/0/d/e/1FAIpQLSe9Vff8oHGMRXcjgCXZwkjvx3eBdNpn4DzjO0FkcWEU1gEQpA/formResponse"
"https://docs.google.com/forms/d/e/1FAIpQLSfO4r353BJ79TTY_-t5KWSIJT2xfqcQWY81xjAA1-1N0U2eSg/formResponse"
val data = mapOf(
"entry.1586460852" to errorContent.toJSON()
"entry.1993829403" to errorContent.toJSON()
)
thread { // to not run it on main thread
runBlocking {
suspendSafeApiCall {
val post = app.post(url, data = data)
println("Report response: $post")
app.post(url, data = data)
//println("Report response: $post")
}
}
}
@ -65,7 +64,6 @@ class CustomReportSender : ReportSender {
}
}
@AutoService(ReportSenderFactory::class)
class CustomSenderFactory : ReportSenderFactory {
override fun create(context: Context, config: CoreConfiguration): ReportSender {
return CustomReportSender()
@ -104,12 +102,17 @@ class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)) :
}
class AcraApplication : Application() {
override fun onCreate() {
super.onCreate()
Thread.setDefaultUncaughtExceptionHandler(ExceptionHandler(filesDir.resolve("last_error")) {
//NativeCrashHandler.initCrashHandler()
ExceptionHandler(filesDir.resolve("last_error")) {
val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName)
startActivity(Intent.makeRestartActivityTask(intent!!.component))
})
}.also {
exceptionHandler = it
Thread.setDefaultUncaughtExceptionHandler(it)
}
}
override fun attachBaseContext(base: Context?) {
@ -121,10 +124,10 @@ class AcraApplication : Application() {
buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.JSON
reportContent = arrayOf(
reportContent = listOf(
ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE,
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
ReportField.STACK_TRACE
ReportField.STACK_TRACE,
)
// removed this due to bug when starting the app, moved it to when it actually crashes
@ -137,6 +140,8 @@ class AcraApplication : Application() {
}
companion object {
var exceptionHandler: ExceptionHandler? = null
/** Use to get activity from Context */
tailrec fun Context.getActivity(): Activity? = this as? Activity
?: (this as? ContextWrapper)?.baseContext?.getActivity()
@ -148,6 +153,14 @@ class AcraApplication : Application() {
_context = WeakReference(value)
}
fun <T : Any> getKeyClass(path: String, valueType: Class<T>): T? {
return context?.getKey(path, valueType)
}
fun <T : Any> setKeyClass(path: String, value: T) {
context?.setKey(path, value)
}
fun removeKeys(folder: String): Int? {
return context?.removeKeys(folder)
}
@ -199,10 +212,9 @@ class AcraApplication : Application() {
fun openBrowser(url: String, activity: FragmentActivity?) {
openBrowser(
url,
isTvSettings(),
isLayout(TV or EMULATOR),
activity?.supportFragmentManager?.fragments?.lastOrNull()
)
}
}
}
}

View File

@ -7,9 +7,13 @@ import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Resources
import android.os.Build
import android.util.DisplayMetrics
import android.util.Log
import android.view.*
import android.widget.TextView
import android.view.Gravity
import android.view.KeyEvent
import android.view.View
import android.view.View.NO_ID
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
@ -18,15 +22,21 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.preference.PreferenceManager
import com.google.android.gms.cast.framework.CastSession
import com.google.android.material.chip.ChipGroup
import com.google.android.material.navigationrail.NavigationRailView
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.MainActivity.Companion.resumeApps
import com.lagradost.cloudstream3.databinding.ToastBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.player.PlayerEventType
import com.lagradost.cloudstream3.ui.result.ResultFragment
import com.lagradost.cloudstream3.ui.result.UiText
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
import com.lagradost.cloudstream3.ui.settings.Globals.updateTv
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.Event
import com.lagradost.cloudstream3.utils.UIHelper
@ -34,14 +44,50 @@ import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import org.schabi.newpipe.extractor.NewPipe
import java.util.*
import java.lang.ref.WeakReference
import java.util.Locale
import kotlin.math.max
import kotlin.math.min
enum class FocusDirection {
Start,
End,
Up,
Down,
}
object CommonActivity {
private var _activity: WeakReference<Activity>? = null
var activity
get() = _activity?.get()
private set(value) {
_activity = WeakReference(value)
}
@MainThread
fun setActivityInstance(newActivity: Activity?) {
activity = newActivity
}
@MainThread
fun Activity?.getCastSession(): CastSession? {
return (this as MainActivity?)?.mSessionManager?.currentCastSession
}
val displayMetrics: DisplayMetrics = Resources.getSystem().displayMetrics
// screenWidth and screenHeight does always
// refer to the screen while in landscape mode
val screenWidth: Int
get() {
return max(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
val screenHeight: Int
get() {
return min(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
var canEnterPipMode: Boolean = false
var canShowPipMode: Boolean = false
@ -53,9 +99,32 @@ object CommonActivity {
var playerEventListener: ((PlayerEventType) -> Unit)? = null
var keyEventListener: ((Pair<KeyEvent?, Boolean>) -> Boolean)? = null
private var currentToast: Toast? = null
var currentToast: Toast? = null
fun showToast(@StringRes message: Int, duration: Int? = null) {
val act = activity ?: return
act.runOnUiThread {
showToast(act, act.getString(message), duration)
}
}
fun showToast(message: String?, duration: Int? = null) {
val act = activity ?: return
act.runOnUiThread {
showToast(act, message, duration)
}
}
fun showToast(message: UiText?, duration: Int? = null) {
val act = activity ?: return
if (message == null) return
act.runOnUiThread {
showToast(act, message.asString(act), duration)
}
}
@MainThread
fun showToast(act: Activity?, text: UiText, duration: Int) {
if (act == null) return
text.asStringNull(act)?.let {
@ -86,25 +155,19 @@ object CommonActivity {
} catch (e: Exception) {
logError(e)
}
try {
val inflater =
act.getSystemService(AppCompatActivity.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val layout: View = inflater.inflate(
R.layout.toast,
act.findViewById<View>(R.id.toast_layout_root) as ViewGroup?
)
val text = layout.findViewById(R.id.text) as TextView
text.text = message.trim()
val binding = ToastBinding.inflate(act.layoutInflater)
binding.text.text = message.trim()
// custom toasts are deprecated and won't appear when cs3 sets minSDK to api30 (A11)
val toast = Toast(act)
toast.setGravity(Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, 0, 5.toPx)
toast.duration = duration ?: Toast.LENGTH_SHORT
toast.view = layout
//https://github.com/PureWriter/ToastCompat
toast.show()
toast.setGravity(Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, 0, 5.toPx)
toast.view = binding.root
currentToast = toast
toast.show()
} catch (e: Exception) {
logError(e)
}
@ -138,22 +201,25 @@ object CommonActivity {
setLocale(this, localeCode)
}
fun init(act: ComponentActivity?) {
if (act == null) return
fun init(act: Activity) {
setActivityInstance(act)
val componentActivity = activity as? ComponentActivity ?: return
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
//https://developer.android.com/guide/topics/ui/picture-in-picture
canShowPipMode =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && // OS SUPPORT
act.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && // HAS FEATURE, MIGHT BE BLOCKED DUE TO POWER DRAIN
act.hasPIPPermission() // CHECK IF FEATURE IS ENABLED IN SETTINGS
componentActivity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && // HAS FEATURE, MIGHT BE BLOCKED DUE TO POWER DRAIN
componentActivity.hasPIPPermission() // CHECK IF FEATURE IS ENABLED IN SETTINGS
act.updateLocale()
act.updateTv()
componentActivity.updateLocale()
componentActivity.updateTv()
NewPipe.init(DownloaderTestImpl.getInstance())
for (resumeApp in resumeApps) {
resumeApp.launcher =
act.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
componentActivity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val resultCode = result.resultCode
val data = result.data
if (resultCode == AppCompatActivity.RESULT_OK && data != null && resumeApp.position != null && resumeApp.duration != null) {
@ -170,11 +236,11 @@ object CommonActivity {
// Ask for notification permissions on Android 13
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
ContextCompat.checkSelfPermission(
act,
componentActivity,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
val requestPermissionLauncher = act.registerForActivityResult(
val requestPermissionLauncher = componentActivity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
Log.d(TAG, "Notification permission: $isGranted")
@ -222,18 +288,22 @@ object CommonActivity {
"AmoledLight" -> R.style.AmoledModeLight
"Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.MonetMode else R.style.AppTheme
else -> R.style.AppTheme
}
val currentOverlayTheme =
when (settingsManager.getString(act.getString(R.string.primary_color_key), "Normal")) {
"Normal" -> R.style.OverlayPrimaryColorNormal
"DandelionYellow" -> R.style.OverlayPrimaryColorDandelionYellow
"CarnationPink" -> R.style.OverlayPrimaryColorCarnationPink
"Orange" -> R.style.OverlayPrimaryColorOrange
"DarkGreen" -> R.style.OverlayPrimaryColorDarkGreen
"Maroon" -> R.style.OverlayPrimaryColorMaroon
"NavyBlue" -> R.style.OverlayPrimaryColorNavyBlue
"Grey" -> R.style.OverlayPrimaryColorGrey
"White" -> R.style.OverlayPrimaryColorWhite
"CoolBlue" -> R.style.OverlayPrimaryColorCoolBlue
"Brown" -> R.style.OverlayPrimaryColorBrown
"Purple" -> R.style.OverlayPrimaryColorPurple
"Green" -> R.style.OverlayPrimaryColorGreen
@ -242,10 +312,13 @@ object CommonActivity {
"Banana" -> R.style.OverlayPrimaryColorBanana
"Party" -> R.style.OverlayPrimaryColorParty
"Pink" -> R.style.OverlayPrimaryColorPink
"Lavender" -> R.style.OverlayPrimaryColorLavender
"Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.OverlayPrimaryColorMonet else R.style.OverlayPrimaryColorNormal
"Monet2" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.OverlayPrimaryColorMonetTwo else R.style.OverlayPrimaryColorNormal
else -> R.style.OverlayPrimaryColorNormal
}
act.theme.applyStyle(currentTheme, true)
@ -257,55 +330,138 @@ object CommonActivity {
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
}
private fun getNextFocus(
act: Activity?,
/** because we want closes find, aka when multiple have the same id, we go to parent
until the correct one is found */
private fun localLook(from: View, id: Int): View? {
if (id == NO_ID) return null
var currentLook: View = from
// limit to 15 look depth
for (i in 0..15) {
currentLook.findViewById<View?>(id)?.let { return it }
currentLook = (currentLook.parent as? View) ?: break
}
return null
}
/*var currentLook: View = view
while (true) {
val tmpNext = currentLook.findViewById<View?>(nextId)
if (tmpNext != null) {
next = tmpNext
break
}
currentLook = currentLook.parent as? View ?: break
}*/
private fun View.hasContent() : Boolean {
return isShown && when(this) {
//is RecyclerView -> this.childCount > 0
is ViewGroup -> this.childCount > 0
else -> true
}
}
/** skips the initial stage of searching for an id using the view, see getNextFocus for specification */
fun continueGetNextFocus(
root: Any?,
view: View,
direction: FocusDirection,
nextId: Int,
depth: Int = 0
): View? {
if (nextId == NO_ID) return null
// do an initial search for the view, in case the localLook is too deep we can use this as
// an early break and backup view
var next =
when (root) {
is Activity -> root.findViewById(nextId)
is View -> root.rootView.findViewById<View?>(nextId)
else -> null
} ?: return null
next = localLook(view, nextId) ?: next
val shown = next.hasContent()
// if cant focus but visible then break and let android decide
// the exception if is the view is a parent and has children that wants focus
val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent ->
parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.childCount > 0
} ?: false
if (!next.isFocusable && shown && !hasChildrenThatWantsFocus) return null
// if not shown then continue because we will "skip" over views to get to a replacement
if (!shown) {
// we don't want a while true loop, so we let android decide if we find a recursive view
if (next == view) return null
return getNextFocus(root, next, direction, depth + 1)
}
(when (next) {
is ChipGroup -> {
next.children.firstOrNull { it.isFocusable && it.isShown }
}
is NavigationRailView -> {
next.findViewById(next.selectedItemId) ?: next.findViewById(R.id.navigation_home)
}
else -> null
})?.let {
return it
}
// nothing wrong with the view found, return it
return next
}
/** recursively looks for a next focus up to a depth of 10,
* this is used to override the normal shit focus system
* because this application has a lot of invisible views that messes with some tv devices*/
fun getNextFocus(
root: Any?,
view: View?,
direction: FocusDirection,
depth: Int = 0
): Int? {
if (view == null || depth >= 10 || act == null) {
): View? {
// if input is invalid let android decide + depth test to not crash if loop is found
if (view == null || depth >= 10 || root == null) {
return null
}
val nextId = when (direction) {
FocusDirection.Left -> {
view.nextFocusLeftId
var nextId = when (direction) {
FocusDirection.Start -> {
if (view.isRtl())
view.nextFocusRightId
else
view.nextFocusLeftId
}
FocusDirection.Up -> {
view.nextFocusUpId
}
FocusDirection.Right -> {
view.nextFocusRightId
FocusDirection.End -> {
if (view.isRtl())
view.nextFocusLeftId
else
view.nextFocusRightId
}
FocusDirection.Down -> {
view.nextFocusDownId
}
}
return if (nextId != -1) {
val next = act.findViewById<View?>(nextId)
//println("NAME: ${next.accessibilityClassName} | ${next?.isShown}" )
if (next?.isShown == false) {
getNextFocus(act, next, direction, depth + 1)
} else {
if (depth == 0) {
null
} else {
nextId
}
}
} else {
null
if (nextId == NO_ID) {
// if not specified then use forward id
nextId = view.nextFocusForwardId
// if view is still not found to next focus then return and let android decide
if (nextId == NO_ID)
return null
}
return continueGetNextFocus(root, view, direction, nextId, depth)
}
enum class FocusDirection {
Left,
Right,
Up,
Down,
}
fun onKeyDown(act: Activity?, keyCode: Int, event: KeyEvent?) {
//println("Keycode: $keyCode")
@ -328,30 +484,39 @@ object CommonActivity {
KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {
PlayerEventType.SeekForward
}
KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
PlayerEventType.SeekBack
}
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1, KeyEvent.KEYCODE_N -> {
PlayerEventType.NextEpisode
}
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_B -> {
PlayerEventType.PrevEpisode
}
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
PlayerEventType.Pause
}
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> {
PlayerEventType.Play
}
KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7, KeyEvent.KEYCODE_7 -> {
PlayerEventType.Lock
}
KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> {
PlayerEventType.ToggleHide
}
KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> {
PlayerEventType.ToggleMute
}
KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9, KeyEvent.KEYCODE_9 -> {
PlayerEventType.ShowMirrors
}
@ -359,21 +524,27 @@ object CommonActivity {
KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_NUMPAD_8, KeyEvent.KEYCODE_8 -> {
PlayerEventType.SearchSubtitlesOnline
}
KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3, KeyEvent.KEYCODE_3 -> {
PlayerEventType.ShowSpeed
}
KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0, KeyEvent.KEYCODE_0 -> {
PlayerEventType.Resize
}
KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4, KeyEvent.KEYCODE_4 -> {
PlayerEventType.SkipOp
}
KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_NUMPAD_5, KeyEvent.KEYCODE_5 -> {
PlayerEventType.SkipCurrentChapter
}
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation
PlayerEventType.PlayPauseToggle
}
else -> null
}?.let { playerEvent ->
playerEventListener?.invoke(playerEvent)
@ -386,64 +557,64 @@ object CommonActivity {
//}
}
/** overrides focus and custom key events */
fun dispatchKeyEvent(act: Activity?, event: KeyEvent?): Boolean? {
if (act == null) return null
val currentFocus = act.currentFocus
event?.keyCode?.let { keyCode ->
when (event.action) {
KeyEvent.ACTION_DOWN -> {
if (act.currentFocus != null) {
val next = when (keyCode) {
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(
act,
act.currentFocus,
FocusDirection.Left
)
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
act,
act.currentFocus,
FocusDirection.Right
)
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
act,
act.currentFocus,
FocusDirection.Up
)
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
act,
act.currentFocus,
FocusDirection.Down
)
if (currentFocus == null || event.action != KeyEvent.ACTION_DOWN) return@let
val nextView = when (keyCode) {
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(
act,
currentFocus,
FocusDirection.Start
)
else -> null
}
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
act,
currentFocus,
FocusDirection.End
)
if (next != null && next != -1) {
val nextView = act.findViewById<View?>(next)
if (nextView != null) {
nextView.requestFocus()
keyEventListener?.invoke(Pair(event, true))
return true
}
}
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
act,
currentFocus,
FocusDirection.Up
)
when (keyCode) {
KeyEvent.KEYCODE_DPAD_CENTER -> {
if (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete) {
UIHelper.showInputMethod(act.currentFocus?.findFocus())
}
}
}
}
//println("Keycode: $keyCode")
//showToast(
// this,
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
// Toast.LENGTH_LONG
//)
}
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
act,
currentFocus,
FocusDirection.Down
)
else -> null
}
// println("NEXT FOCUS : $nextView")
if (nextView != null) {
nextView.requestFocus()
keyEventListener?.invoke(Pair(event, true))
return true
}
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER &&
(act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete)
) {
UIHelper.showInputMethod(act.currentFocus?.findFocus())
}
//println("Keycode: $keyCode")
//showToast(
// this,
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
// Toast.LENGTH_LONG
//)
}
// if someone else want to override the focus then don't handle the event as it is already
// consumed. used in video player
if (keyEventListener?.invoke(Pair(event, false)) == true) {
return true
}

View File

@ -50,7 +50,7 @@ class DownloaderTestImpl private constructor(builder: OkHttpClient.Builder) : Do
companion object {
private const val USER_AGENT =
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
private var instance: DownloaderTestImpl? = null
/**

View File

@ -9,33 +9,38 @@ import androidx.preference.PreferenceManager
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.kotlinModule
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklApi
import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.syncproviders.providers.SimklApi
import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.Coroutines.mainWork
import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.nicehttp.RequestBodyTypes
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.absoluteValue
const val USER_AGENT =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
val mapper = JsonMapper.builder().addModule(KotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
/**
* Defines the constant for the all languages preference, if this is set then it is
* the equivalent of all languages being set
**/
const val AllLanguagesName = "universal"
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
val mapper = JsonMapper.builder().addModule(kotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
object APIHolder {
val unixTime: Long
get() = System.currentTimeMillis() / 1000L
@ -48,8 +53,10 @@ object APIHolder {
val allProviders = threadSafeListOf<MainAPI>()
fun initAll() {
for (api in allProviders) {
api.init()
synchronized(allProviders) {
for (api in allProviders) {
api.init()
}
}
apiMap = null
}
@ -62,27 +69,35 @@ object APIHolder {
var apiMap: Map<String, Int>? = null
fun addPluginMapping(plugin: MainAPI) {
apis = apis + plugin
synchronized(apis) {
apis = apis + plugin
}
initMap(true)
}
fun removePluginMapping(plugin: MainAPI) {
apis = apis.filter { it != plugin }
synchronized(apis) {
apis = apis.filter { it != plugin }
}
initMap(true)
}
private fun initMap(forcedUpdate: Boolean = false) {
if (apiMap == null || forcedUpdate)
apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap()
synchronized(apis) {
if (apiMap == null || forcedUpdate)
apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap()
}
}
fun getApiFromNameNull(apiName: String?): MainAPI? {
if (apiName == null) return null
synchronized(allProviders) {
initMap()
return apiMap?.get(apiName)?.let { apis.getOrNull(it) }
synchronized(apis) {
return apiMap?.get(apiName)?.let { apis.getOrNull(it) }
// Leave the ?. null check, it can crash regardless
?: allProviders.firstOrNull { it?.name == apiName }
?: allProviders.firstOrNull { it.name == apiName }
}
}
}
@ -102,7 +117,9 @@ object APIHolder {
}
fun LoadResponse.getId(): Int {
return getLoadResponseIdFromUrl(url, apiName)
// this fixes an issue with outdated api as getLoadResponseIdFromUrl might be fucked
return (if (this is ResultViewModel2.LoadResponseFromSearch) this.id else null)
?: getLoadResponseIdFromUrl(url, apiName)
}
/**
@ -160,13 +177,113 @@ object APIHolder {
return null
}
private var trackerCache: HashMap<String, AniSearch> = hashMapOf()
/** backwards compatibility, use getTracker4 instead */
suspend fun getTracker(
titles: List<String>,
types: Set<TrackerType>?,
year: Int?,
): Tracker? = getTracker(titles, types, year, false)
/**
* Get anime tracker information based on title, year and type.
* Both titles are attempted to be matched with both Romaji and English title.
* Uses the anilist api.
*
* @param titles uses first index to search, but if you have multiple titles and want extra guarantee to match you can also have that
* @param types Optional parameter to narrow down the scope to Movies, TV, etc. See TrackerType.getTypes()
* @param year Optional parameter to only get anime with a specific year
**/
suspend fun getTracker(
titles: List<String>,
types: Set<TrackerType>?,
year: Int?,
lessAccurate: Boolean
): Tracker? {
return try {
require(titles.isNotEmpty()) { "titles must no be empty when calling getTracker" }
val mainTitle = titles[0]
val search =
trackerCache[mainTitle]
?: searchAnilist(mainTitle)?.also {
trackerCache[mainTitle] = it
} ?: return null
val res = search.data?.page?.media?.find { media ->
val matchingYears = year == null || media.seasonYear == year
val matchingTitles = media.title?.let { title ->
titles.any { userTitle ->
title.isMatchingTitles(userTitle)
}
} ?: false
val matchingTypes = types?.any { it.name.equals(media.format, true) } == true
if (lessAccurate) matchingTitles || matchingTypes && matchingYears else matchingTitles && matchingTypes && matchingYears
} ?: return null
Tracker(
res.idMal,
res.id.toString(),
res.coverImage?.extraLarge ?: res.coverImage?.large,
res.bannerImage
)
} catch (t: Throwable) {
logError(t)
null
}
}
private suspend fun searchAnilist(
title: String?,
): AniSearch? {
val query = """
query (
${'$'}page: Int = 1
${'$'}search: String
${'$'}sort: [MediaSort] = [POPULARITY_DESC, SCORE_DESC]
${'$'}type: MediaType
) {
Page(page: ${'$'}page, perPage: 20) {
media(
search: ${'$'}search
sort: ${'$'}sort
type: ${'$'}type
) {
id
idMal
title { romaji english }
coverImage { extraLarge large }
bannerImage
seasonYear
format
}
}
}
""".trimIndent().trim()
val data = mapOf(
"query" to query,
"variables" to mapOf(
"search" to title,
"sort" to "SEARCH_MATCH",
"type" to "ANIME",
)
).toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())
return app.post("https://graphql.anilist.co", requestBody = data)
.parsedSafe()
}
fun Context.getApiSettings(): HashSet<String> {
//val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val hashSet = HashSet<String>()
val activeLangs = getApiProviderLangSettings()
val hasUniversal = activeLangs.contains(AllLanguagesName)
hashSet.addAll(apis.filter { hasUniversal || activeLangs.contains(it.lang) }
hashSet.addAll(synchronized(apis) { apis.filter { hasUniversal || activeLangs.contains(it.lang) } }
.map { it.name })
/*val set = settingsManager.getStringSet(
@ -265,8 +382,9 @@ object APIHolder {
} ?: default
val langs = this.getApiProviderLangSettings()
val hasUniversal = langs.contains(AllLanguagesName)
val allApis = apis.filter { hasUniversal || langs.contains(it.lang) }
.filter { api -> api.hasMainPage || !hasHomePageIsRequired }
val allApis = synchronized(apis) {
apis.filter { api -> (hasUniversal || langs.contains(api.lang)) && (api.hasMainPage || !hasHomePageIsRequired) }
}
return if (currentPrefMedia.isEmpty()) {
allApis
} else {
@ -318,6 +436,57 @@ object APIHolder {
}
}
/*
// THIS IS WORK IN PROGRESS API
interface ITag {
val name: UiText
}
data class SimpleTag(override val name: UiText, val data: String) : ITag
enum class SelectType {
SingleSelect,
MultiSelect,
MultiSelectAndExclude,
}
enum class SelectValue {
Selected,
Excluded,
}
interface GenreSelector {
val title: UiText
val id : Int
}
data class TagSelector(
override val title: UiText,
override val id : Int,
val tags: Set<ITag>,
val defaultTags : Set<ITag> = setOf(),
val selectType: SelectType = SelectType.SingleSelect,
) : GenreSelector
data class BoolSelector(
override val title: UiText,
override val id : Int,
val defaultValue : Boolean = false,
) : GenreSelector
data class InputField(
override val title: UiText,
override val id : Int,
val hint : UiText? = null,
) : GenreSelector
// This response describes how a user might filter the homepage or search results
data class GenreResponse(
val searchSelectors : List<GenreSelector>,
val filterSelectors: List<GenreSelector> = searchSelectors
) */
/*
0 = Site not good
@ -459,6 +628,20 @@ abstract class MainAPI {
open val hasMainPage = false
open val hasQuickSearch = false
/**
* A set of which ids the provider can open with getLoadUrl()
* If the set contains SyncIdName.Imdb then getLoadUrl() can be started with
* an Imdb class which inherits from SyncId.
*
* getLoadUrl() is then used to get page url based on that ID.
*
* Example:
* "tt6723592" -> getLoadUrl(ImdbSyncId("tt6723592")) -> "mainUrl/imdb/tt6723592" -> load("mainUrl/imdb/tt6723592")
*
* This is used to launch pages from personal lists or recommendations using IDs.
**/
open val supportedSyncNames = setOf<SyncIdName>()
open val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
@ -529,6 +712,14 @@ abstract class MainAPI {
open fun getVideoInterceptor(extractorLink: ExtractorLink): Interceptor? {
return null
}
/**
* Get the load() url based on a sync ID like IMDb or MAL.
* Only contains SyncIds based on supportedSyncUrls.
**/
open suspend fun getLoadUrl(name: SyncIdName, id: String): String? {
return null
}
}
/** Might need a different implementation for desktop*/
@ -555,8 +746,6 @@ fun base64Encode(array: ByteArray): String {
}
}
class ErrorLoadingException(message: String? = null) : Exception(message)
fun MainAPI.fixUrlNull(url: String?): String? {
if (url.isNullOrEmpty()) {
return null
@ -615,6 +804,20 @@ fun fixTitle(str: String): String {
}
}
/**
* Get rhino context in a safe way as it needs to be initialized on the main thread.
* Make sure you get the scope using: val scope: Scriptable = rhino.initSafeStandardObjects()
* Use like the following: rhino.evaluateString(scope, js, "JavaScript", 1, null)
**/
suspend fun getRhinoContext(): org.mozilla.javascript.Context {
return Coroutines.mainWork {
val rhino = org.mozilla.javascript.Context.enter()
rhino.initSafeStandardObjects()
rhino.optimizationLevel = -1
rhino
}
}
/** https://www.imdb.com/title/tt2861424/ -> tt2861424 */
fun imdbUrlToId(url: String): String? {
return Regex("/title/(tt[0-9]*)").find(url)?.groupValues?.get(1)
@ -663,7 +866,25 @@ enum class TvType(value: Int?) {
AsianDrama(9),
Live(10),
NSFW(11),
Others(12)
Others(12),
Music(13),
AudioBook(14),
/** Wont load the built in player, make your own interaction */
CustomMedia(15),
}
public enum class AutoDownloadMode(val value: Int) {
Disable(0),
FilterByLang(1),
All(2),
NsfwOnly(3)
;
companion object {
infix fun getEnum(value: Int): AutoDownloadMode? =
AutoDownloadMode.values().firstOrNull { it.value == value }
}
}
// IN CASE OF FUTURE ANIME MOVIE OR SMTH
@ -980,14 +1201,16 @@ interface LoadResponse {
var syncData: MutableMap<String, String>
var posterHeaders: Map<String, String>?
var backgroundPosterUrl: String?
var contentRating: String?
companion object {
private val malIdPrefix = malApi.idPrefix
private val aniListIdPrefix = aniListApi.idPrefix
private val simklIdPrefix = simklApi.idPrefix
var isTrailersEnabled = true
fun LoadResponse.isMovie(): Boolean {
return this.type.isMovieType()
return this.type.isMovieType() || this is MovieLoadResponse
}
@JvmName("addActorNames")
@ -1005,6 +1228,20 @@ interface LoadResponse {
this.actors = actors?.map { (actor, role) -> ActorData(actor, role = role) }
}
/**
* Internal helper function to add simkl ids from other databases.
*/
private fun LoadResponse.addSimklId(
database: SimklApi.Companion.SyncServices,
id: String?
) {
normalSafeApiCall {
this.syncData[simklIdPrefix] =
SimklApi.addIdToString(this.syncData[simklIdPrefix], database, id.toString())
?: return@normalSafeApiCall
}
}
@JvmName("addActorsOnly")
fun LoadResponse.addActors(actors: List<Actor>?) {
this.actors = actors?.map { actor -> ActorData(actor) }
@ -1018,12 +1255,32 @@ interface LoadResponse {
return this.syncData[aniListIdPrefix]
}
fun LoadResponse.getImdbId(): String? {
return normalSafeApiCall {
SimklApi.readIdFromString(this.syncData[simklIdPrefix])
?.get(SimklApi.Companion.SyncServices.Imdb)
}
}
fun LoadResponse.getTMDbId(): String? {
return normalSafeApiCall {
SimklApi.readIdFromString(this.syncData[simklIdPrefix])
?.get(SimklApi.Companion.SyncServices.Tmdb)
}
}
fun LoadResponse.addMalId(id: Int?) {
this.syncData[malIdPrefix] = (id ?: return).toString()
this.addSimklId(SimklApi.Companion.SyncServices.Mal, id.toString())
}
fun LoadResponse.addAniListId(id: Int?) {
this.syncData[aniListIdPrefix] = (id ?: return).toString()
this.addSimklId(SimklApi.Companion.SyncServices.AniList, id.toString())
}
fun LoadResponse.addSimklId(id: Int?) {
this.addSimklId(SimklApi.Companion.SyncServices.Simkl, id.toString())
}
fun LoadResponse.addImdbUrl(url: String?) {
@ -1105,6 +1362,7 @@ interface LoadResponse {
fun LoadResponse.addImdbId(id: String?) {
// TODO add imdb sync
this.addSimklId(SimklApi.Companion.SyncServices.Imdb, id)
}
fun LoadResponse.addTrackId(id: String?) {
@ -1117,6 +1375,7 @@ interface LoadResponse {
fun LoadResponse.addTMDbId(id: String?) {
// TODO add TMDb sync
this.addSimklId(SimklApi.Companion.SyncServices.Tmdb, id)
}
fun LoadResponse.addRating(text: String?) {
@ -1192,14 +1451,27 @@ fun LoadResponse?.isAnimeBased(): Boolean {
fun TvType?.isEpisodeBased(): Boolean {
if (this == null) return false
return (this == TvType.TvSeries || this == TvType.Anime)
return (this == TvType.TvSeries || this == TvType.Anime || this == TvType.AsianDrama)
}
data class NextAiring(
val episode: Int,
val unixTime: Long,
)
val season: Int? = null,
) {
/**
* Secondary constructor for backwards compatibility without season.
* TODO Remove this constructor after there is a new stable release and extensions are updated to support season.
*/
constructor(
episode: Int,
unixTime: Long,
) : this (
episode,
unixTime,
null
)
}
/**
* @param season To be mapped with episode season, not shown in UI if displaySeason is defined
@ -1216,6 +1488,16 @@ interface EpisodeResponse {
var showStatus: ShowStatus?
var nextAiring: NextAiring?
var seasonNames: List<SeasonData>?
fun getLatestEpisodes(): Map<DubStatus, Int?>
/** Count all episodes in all previous seasons up until this episode to get a total count.
* Example:
* Season 1: 10 episodes.
* Season 2: 6 episodes.
*
* getTotalEpisodeIndex(episode = 3, season = 2) -> 10 + 3 = 13
* */
fun getTotalEpisodeIndex(episode: Int, season: Int): Int
}
@JvmName("addSeasonNamesString")
@ -1253,7 +1535,55 @@ data class TorrentLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
magnet: String?,
torrent: String?,
plot: String?,
type: TvType = TvType.Torrent,
posterUrl: String? = null,
year: Int? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name,
url,
apiName,
magnet,
torrent,
plot,
type,
posterUrl,
year,
rating,
tags,
duration,
trailers,
recommendations,
actors,
comingSoon,
syncData,
posterHeaders,
backgroundPosterUrl,
null
)
}
data class AnimeLoadResponse(
var engName: String? = null,
@ -1284,7 +1614,90 @@ data class AnimeLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List<SeasonData>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse, EpisodeResponse
override var contentRating: String? = null,
) : LoadResponse, EpisodeResponse {
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
return episodes.map { (status, episodes) ->
val maxSeason = episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }
.takeUnless { it == Int.MIN_VALUE }
status to episodes
.filter { it.season == maxSeason }
.maxOfOrNull { it.episode ?: Int.MIN_VALUE }
.takeUnless { it == Int.MIN_VALUE }
}.toMap()
}
override fun getTotalEpisodeIndex(episode: Int, season: Int): Int {
val displayMap = this.seasonNames?.associate { it.season to it.displaySeason } ?: emptyMap()
return this.episodes.maxOf { (_, episodes) ->
episodes.count { episodeData ->
// Prioritize display season as actual season may be something random to fit multiple seasons into one.
val episodeSeason =
displayMap[episodeData.season] ?: episodeData.season ?: Int.MIN_VALUE
// Count all episodes from season 1 to below the current season.
episodeSeason in 1..<season
}
} + episode
}
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
engName: String? = null,
japName: String? = null,
name: String,
url: String,
apiName: String,
type: TvType,
posterUrl: String? = null,
year: Int? = null,
episodes: MutableMap<DubStatus, List<Episode>> = mutableMapOf(),
showStatus: ShowStatus? = null,
plot: String? = null,
tags: List<String>? = null,
synonyms: List<String>? = null,
rating: Int? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
nextAiring: NextAiring? = null,
seasonNames: List<SeasonData>? = null,
backgroundPosterUrl: String? = null,
) : this(
engName,
japName,
name,
url,
apiName,
type,
posterUrl,
year,
episodes,
showStatus,
plot,
tags,
synonyms,
rating,
duration,
trailers,
recommendations,
actors,
comingSoon,
syncData,
posterHeaders,
nextAiring,
seasonNames,
backgroundPosterUrl,
null
)
}
/**
* If episodes already exist appends the list.
@ -1335,7 +1748,36 @@ data class LiveStreamLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
dataUrl: String,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
type: TvType = TvType.Live,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, dataUrl, posterUrl, year, plot, type, rating, tags, duration, trailers,
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
)
}
data class MovieLoadResponse(
override var name: String,
@ -1358,7 +1800,36 @@ data class MovieLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
type: TvType,
dataUrl: String,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, type, dataUrl, posterUrl, year, plot, rating, tags, duration, trailers,
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
)
}
suspend fun <T> MainAPI.newMovieLoadResponse(
name: String,
@ -1482,7 +1953,81 @@ data class TvSeriesLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List<SeasonData>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse, EpisodeResponse
override var contentRating: String? = null,
) : LoadResponse, EpisodeResponse {
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
val maxSeason =
episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }.takeUnless { it == Int.MIN_VALUE }
val max = episodes
.filter { it.season == maxSeason }
.maxOfOrNull { it.episode ?: Int.MIN_VALUE }
.takeUnless { it == Int.MIN_VALUE }
return mapOf(DubStatus.None to max)
}
override fun getTotalEpisodeIndex(episode: Int, season: Int): Int {
val displayMap = this.seasonNames?.associate { it.season to it.displaySeason } ?: emptyMap()
return episodes.count { episodeData ->
// Prioritize display season as actual season may be something random to fit multiple seasons into one.
val episodeSeason =
displayMap[episodeData.season] ?: episodeData.season ?: Int.MIN_VALUE
// Count all episodes from season 1 to below the current season.
episodeSeason in 1..<season
} + episode
}
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
type: TvType,
episodes: List<Episode>,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
showStatus: ShowStatus? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
nextAiring: NextAiring? = null,
seasonNames: List<SeasonData>? = null,
backgroundPosterUrl: String? = null,
) : this(
name,
url,
apiName,
type,
episodes,
posterUrl,
year,
plot,
showStatus,
rating,
tags,
duration,
trailers,
recommendations,
actors,
comingSoon,
syncData,
posterHeaders,
nextAiring,
seasonNames,
backgroundPosterUrl,
null
)
}
suspend fun MainAPI.newTvSeriesLoadResponse(
name: String,
@ -1514,3 +2059,74 @@ fun fetchUrls(text: String?): List<String> {
fun String?.toRatingInt(): Int? =
this?.replace(" ", "")?.trim()?.toDoubleOrNull()?.absoluteValue?.times(1000f)?.toInt()
data class Tracker(
val malId: Int? = null,
val aniId: String? = null,
val image: String? = null,
val cover: String? = null,
)
data class AniSearch(
@JsonProperty("data") var data: Data? = Data()
) {
data class Data(
@JsonProperty("Page") var page: Page? = Page()
) {
data class Page(
@JsonProperty("media") var media: ArrayList<Media> = arrayListOf()
) {
data class Media(
@JsonProperty("title") var title: Title? = null,
@JsonProperty("id") var id: Int? = null,
@JsonProperty("idMal") var idMal: Int? = null,
@JsonProperty("seasonYear") var seasonYear: Int? = null,
@JsonProperty("format") var format: String? = null,
@JsonProperty("coverImage") var coverImage: CoverImage? = null,
@JsonProperty("bannerImage") var bannerImage: String? = null,
) {
data class CoverImage(
@JsonProperty("extraLarge") var extraLarge: String? = null,
@JsonProperty("large") var large: String? = null,
)
data class Title(
@JsonProperty("romaji") var romaji: String? = null,
@JsonProperty("english") var english: String? = null,
) {
fun isMatchingTitles(title: String?): Boolean {
if (title == null) return false
return english.equals(title, true) || romaji.equals(title, true)
}
}
}
}
}
}
/**
* used for the getTracker() method
**/
enum class TrackerType {
MOVIE,
TV,
TV_SHORT,
ONA,
OVA,
SPECIAL,
MUSIC;
companion object {
fun getTypes(type: TvType): Set<TrackerType> {
return when (type) {
TvType.Movie -> setOf(MOVIE)
TvType.AnimeMovie -> setOf(MOVIE)
TvType.TvSeries -> setOf(TV, TV_SHORT)
TvType.Anime -> setOf(TV, TV_SHORT, ONA, OVA)
TvType.OVA -> setOf(OVA, SPECIAL, ONA)
TvType.Others -> setOf(MUSIC)
else -> emptySet()
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
package com.lagradost.cloudstream3
import com.lagradost.cloudstream3.MainActivity.Companion.lastError
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.plugins.PluginManager.checkSafeModeFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
object NativeCrashHandler {
// external fun triggerNativeCrash()
/*private external fun initNativeCrashHandler()
private external fun getSignalStatus(): Int
private fun initSignalPolling() = CoroutineScope(Dispatchers.IO).launch {
//launch {
// delay(10000)
// triggerNativeCrash()
//}
while (true) {
delay(10_000)
val signal = getSignalStatus()
// Signal is initialized to zero
if (signal == 0) continue
// Do not crash in safe mode!
if (lastError != null) continue
if (checkSafeModeFile()) continue
AcraApplication.exceptionHandler?.uncaughtException(
Thread.currentThread(),
RuntimeException("Native crash with code: $signal. Try uninstalling extensions.\n")
)
}
}
fun initCrashHandler() {
try {
System.loadLibrary("native-lib")
initNativeCrashHandler()
} catch (t: Throwable) {
// Make debug crash.
if (BuildConfig.DEBUG) throw t
logError(t)
return
}
initSignalPolling()
}*/
}

View File

@ -1,7 +1,7 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.utils.*
open class Acefile : ExtractorApi() {
@ -9,31 +9,35 @@ open class Acefile : ExtractorApi() {
override val mainUrl = "https://acefile.co"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val sources = mutableListOf<ExtractorLink>()
app.get(url).document.select("script").map { script ->
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
val data = getAndUnpack(script.data())
val id = data.substringAfter("{\"id\":\"").substringBefore("\",")
val key = data.substringAfter("var nfck=\"").substringBefore("\";")
app.get("https://acefile.co/local/$id?key=$key").text.let {
base64Decode(
it.substringAfter("JSON.parse(atob(\"").substringBefore("\"))")
).let { res ->
sources.add(
ExtractorLink(
name,
name,
res.substringAfter("\"file\":\"").substringBefore("\","),
"$mainUrl/",
Qualities.Unknown.value,
)
)
}
}
}
}
return sources
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = "/(?:d|download|player|f|file)/(\\w+)".toRegex().find(url)?.groupValues?.get(1)
val script = getAndUnpack(app.get("$mainUrl/player/${id ?: return}").text)
val service = """service\s*=\s*['"]([^'"]+)""".toRegex().find(script)?.groupValues?.get(1)
val serverUrl = """['"](\S+check&id\S+?)['"]""".toRegex().find(script)?.groupValues?.get(1)
?.replace("\"+service+\"", service ?: return)
val video = app.get(serverUrl ?: return, referer = "$mainUrl/").parsedSafe<Source>()?.data
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"",
Qualities.Unknown.value,
INFER_TYPE
)
)
}
data class Source(
val data: String? = null,
)
}

View File

@ -9,7 +9,7 @@ import java.net.URI
open class AsianLoad : ExtractorApi() {
override var name = "AsianLoad"
override var mainUrl = "https://asianembed.io"
override var mainUrl = "https://asianhdplay.pro"
override val requiresReferer = true
private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*?["'](.*?)["']""")
@ -43,4 +43,4 @@ open class AsianLoad : ExtractorApi() {
return extractedLinksList
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.utils.*
open class ByteShare : ExtractorApi() {
override val name = "ByteShare"
override val mainUrl = "https://byteshare.to"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val sources = mutableListOf<ExtractorLink>()
sources.add(
ExtractorLink(
name,
name,
url.replace("/embed/", "/download/"),
"",
Qualities.Unknown.value,
)
)
return sources
}
}

View File

@ -1,13 +1,11 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import android.util.Log
import com.lagradost.cloudstream3.utils.Qualities
import java.net.URLDecoder
open class Cda: ExtractorApi() {

View File

@ -0,0 +1,107 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
class Moviesapi : Chillx() {
override val name = "Moviesapi"
override val mainUrl = "https://w1.moviesapi.club"
}
class Bestx : Chillx() {
override val name = "Bestx"
override val mainUrl = "https://bestx.stream"
}
class Watchx : Chillx() {
override val name = "Watchx"
override val mainUrl = "https://watchx.top"
}
open class Chillx : ExtractorApi() {
override val name = "Chillx"
override val mainUrl = "https://chillx.top"
override val requiresReferer = true
companion object {
private var key: String? = null
suspend fun fetchKey(): String {
return if (key != null) {
key!!
} else {
val fetch = app.get("https://raw.githubusercontent.com/rushi-chavan/multi-keys/keys/keys.json").parsedSafe<Keys>()?.key?.get(0) ?: throw ErrorLoadingException("Unable to get key")
key = fetch
key!!
}
}
}
@Suppress("NAME_SHADOWING")
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val master = Regex("""JScript[\w+]?\s*=\s*'([^']+)""").find(
app.get(
url,
referer = url,
).text
)?.groupValues?.get(1)
val key = fetchKey()
val decrypt = cryptoAESHandler(master ?: "", key.toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
val subtitles = Regex("""subtitle"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
val subtitlePattern = """\[(.*?)](https?://[^\s,]+)""".toRegex()
val matches = subtitlePattern.findAll(subtitles ?: "")
val languageUrlPairs = matches.map { matchResult ->
val (language, url) = matchResult.destructured
decodeUnicodeEscape(language) to url
}.toList()
languageUrlPairs.forEach{ (name, file) ->
subtitleCallback.invoke(
SubtitleFile(
name,
file
)
)
}
// required
val headers = mapOf(
"Accept" to "*/*",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",
"Origin" to mainUrl,
)
M3u8Helper.generateM3u8(
name,
source ?: return,
"$mainUrl/",
headers = headers
).forEach(callback)
}
private fun decodeUnicodeEscape(input: String): String {
val regex = Regex("u([0-9a-fA-F]{4})")
return regex.replace(input) {
it.groupValues[1].toInt(16).toChar().toString()
}
}
data class Keys(
@JsonProperty("chillx") val key: List<String>
)
}

View File

@ -0,0 +1,69 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class ContentX : ExtractorApi() {
override val name = "ContentX"
override val mainUrl = "https://contentx.me"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
Log.d("Kekik_${this.name}", "url » ${url}")
val i_source = app.get(url, referer=ext_ref).text
val i_extract = Regex("""window\.openPlayer\('([^']+)'""").find(i_source)!!.groups[1]?.value ?: throw ErrorLoadingException("i_extract is null")
val sub_urls = mutableSetOf<String>()
Regex("""\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(i_source).forEach {
val (sub_url, sub_lang) = it.destructured
if (sub_url in sub_urls) { return@forEach }
sub_urls.add(sub_url)
subtitleCallback.invoke(
SubtitleFile(
lang = sub_lang.replace("\\u0131", "ı").replace("\\u0130", "İ").replace("\\u00fc", "ü").replace("\\u00e7", "ç"),
url = fixUrl(sub_url.replace("\\", ""))
)
)
}
val vid_source = app.get("${mainUrl}/source2.php?v=${i_extract}", referer=ext_ref).text
val vid_extract = Regex("""file\":\"([^\"]+)""").find(vid_source)!!.groups[1]?.value ?: throw ErrorLoadingException("vid_extract is null")
val m3u_link = vid_extract.replace("\\", "")
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = m3u_link,
referer = url,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
val i_dublaj = Regex(""",\"([^']+)\",\"Türkçe""").find(i_source)!!.groups[1]?.value
if (i_dublaj != null) {
val dublaj_source = app.get("${mainUrl}/source2.php?v=${i_dublaj}", referer=ext_ref).text
val dublaj_extract = Regex("""file\":\"([^\"]+)""").find(dublaj_source)!!.groups[1]?.value ?: throw ErrorLoadingException("dublaj_extract is null")
val dublaj_link = dublaj_extract.replace("\\", "")
callback.invoke(
ExtractorLink(
source = "${this.name} Türkçe Dublaj",
name = "${this.name} Türkçe Dublaj",
url = dublaj_link,
referer = url,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
}
}

View File

@ -6,13 +6,19 @@ import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import java.net.URL
class Geodailymotion : Dailymotion() {
override val name = "GeoDailymotion"
override val mainUrl = "https://geo.dailymotion.com"
}
open class Dailymotion : ExtractorApi() {
override val mainUrl = "https://www.dailymotion.com"
override val name = "Dailymotion"
override val requiresReferer = false
private val baseUrl = "https://www.dailymotion.com"
@Suppress("RegExpSimplifiable")
private val videoIdRegex = "^[kx][a-zA-Z0-9]+\$".toRegex()
@ -26,68 +32,68 @@ open class Dailymotion : ExtractorApi() {
callback: (ExtractorLink) -> Unit
) {
val embedUrl = getEmbedUrl(url) ?: return
val doc = app.get(embedUrl).document
val req = app.get(embedUrl)
val prefix = "window.__PLAYER_CONFIG__ = "
val configStr = doc.selectFirst("script:containsData($prefix)")?.data() ?: return
val config = tryParseJson<Config>(configStr.substringAfter(prefix)) ?: return
val configStr = req.document.selectFirst("script:containsData($prefix)")?.data() ?: return
val config = tryParseJson<Config>(configStr.substringAfter(prefix).substringBefore(";").trim()) ?: return
val id = getVideoId(embedUrl) ?: return
val dmV1st = config.dmInternalData.v1st
val dmTs = config.dmInternalData.ts
val metaDataUrl =
"$mainUrl/player/metadata/video/$id?locale=en&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
val cookies = mapOf(
"v1st" to dmV1st,
"dmvk" to config.context.dmvk,
"ts" to dmTs.toString()
)
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = cookies)
val embedder = config.context.embedder
val metaDataUrl = "$baseUrl/player/metadata/video/$id?embedder=$embedder&locale=en-US&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = req.cookies)
.parsedSafe<MetaData>() ?: return
metaData.qualities.forEach { (key, video) ->
metaData.qualities.forEach { (_, video) ->
video.forEach {
callback.invoke(
ExtractorLink(
name,
"$name $key",
it.url,
"",
Qualities.Unknown.value,
true
)
)
getStream(it.url, this.name, callback)
}
}
}
private fun getEmbedUrl(url: String): String? {
if (url.contains("/embed/")) {
return url
}
val vid = getVideoId(url) ?: return null
return "$mainUrl/embed/video/$vid"
if (url.contains("/embed/") || url.contains("/video/")) {
return url
}
if (url.contains("geo.dailymotion.com")) {
val videoId = url.substringAfter("video=")
return "$baseUrl/embed/video/$videoId"
}
return null
}
private fun getVideoId(url: String): String? {
val path = URL(url).path
val id = path.substringAfter("video/")
val id = path.substringAfter("/video/")
if (id.matches(videoIdRegex)) {
return id
}
return null
}
private suspend fun getStream(
streamLink: String,
name: String,
callback: (ExtractorLink) -> Unit
) {
return generateM3u8(
name,
streamLink,
"",
).forEach(callback)
}
data class Config(
val context: Context,
val dmInternalData: InternalData
)
data class InternalData(
val ts: Int,
val ts: Long,
val v1st: String
)
data class Context(
@JsonProperty("access_token") val accessToken: String?,
val dmvk: String,
val embedder: String?,
)
data class MetaData(

View File

@ -7,6 +7,10 @@ import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getQualityFromName
import kotlinx.coroutines.delay
class Dooood : DoodLaExtractor() {
override var mainUrl = "https://dooood.com"
}
class DoodWfExtractor : DoodLaExtractor() {
override var mainUrl = "https://dood.wf"
}
@ -38,6 +42,9 @@ class DoodWsExtractor : DoodLaExtractor() {
override var mainUrl = "https://dood.ws"
}
class DoodYtExtractor : DoodLaExtractor() {
override var mainUrl = "https://dood.yt"
}
open class DoodLaExtractor : ExtractorApi() {
override var name = "DoodStream"
@ -55,7 +62,7 @@ open class DoodLaExtractor : ExtractorApi() {
val quality = Regex("\\d{3,4}p").find(response0.substringAfter("<title>").substringBefore("</title>"))?.groupValues?.get(0)
return listOf(
ExtractorLink(
trueUrl,
this.name,
this.name,
trueUrl,
mainUrl,

View File

@ -0,0 +1,27 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
open class EPlayExtractor : ExtractorApi() {
override var name = "EPlay"
override var mainUrl = "https://eplayvid.net"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val response = app.get(url).document
val trueUrl = response.select("source").attr("src")
return listOf(
ExtractorLink(
this.name,
this.name,
trueUrl,
mainUrl,
getQualityFromName(""), // this needs to be auto
false
)
)
}
}

View File

@ -0,0 +1,39 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class EmturbovidExtractor : ExtractorApi() {
override var name = "Emturbovid"
override var mainUrl = "https://emturbovid.com"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val response = app.get(
url, referer = referer ?: "$mainUrl/"
)
val playerScript =
response.document.selectXpath("//script[contains(text(),'var urlPlay')]")
.html()
val sources = mutableListOf<ExtractorLink>()
if (playerScript.isNotBlank()) {
val m3u8Url =
playerScript.substringAfter("var urlPlay = '").substringBefore("'")
sources.add(
ExtractorLink(
source = name,
name = name,
url = m3u8Url,
referer = "$mainUrl/",
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
return sources
}
}

View File

@ -16,26 +16,7 @@ open class Evoload : ExtractorApi() {
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val lang = url.substring(0, 2)
val flag =
if (lang == "vo") {
" \uD83C\uDDEC\uD83C\uDDE7"
}
else if (lang == "vf"){
" \uD83C\uDDE8\uD83C\uDDF5"
} else {
""
}
val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
url
} else {
url.substring(2, url.length)
}
//println(lang)
//println(cleaned_url)
val id = cleaned_url.replace("https://evoload.io/e/", "") // wanted media id
val id = url.replace("https://evoload.io/e/", "") // wanted media id
val csrv_token = app.get("https://csrv.evosrv.com/captcha?m412548=").text // whatever that is
val captchaPass = app.get("https://cd2.evosrv.com/html/jsx/e.jsx").text.take(300).split("captcha_pass = '")[1].split("\'")[0] //extract the captcha pass from the js response (located in the 300 first chars)
val payload = mapOf("code" to id, "csrv_token" to csrv_token, "pass" to captchaPass)
@ -44,9 +25,9 @@ open class Evoload : ExtractorApi() {
return listOf(
ExtractorLink(
name,
name + flag,
name,
link,
cleaned_url,
url,
Qualities.Unknown.value,
)
)

View File

@ -1,38 +1,83 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
class Guccihide : Filesim() {
override val name = "Guccihide"
override var mainUrl = "https://guccihide.com"
}
class Ahvsh : Filesim() {
override val name = "Ahvsh"
override var mainUrl = "https://ahvsh.com"
}
class Moviesm4u : Filesim() {
override val mainUrl = "https://moviesm4u.com"
override val name = "Moviesm4u"
}
class FileMoonIn : Filesim() {
override val mainUrl = "https://filemoon.in"
override val name = "FileMoon"
}
class StreamhideTo : Filesim() {
override val mainUrl = "https://streamhide.to"
override val name = "Streamhide"
}
class StreamhideCom : Filesim() {
override var name: String = "Streamhide"
override var mainUrl: String = "https://streamhide.com"
}
class Movhide : Filesim() {
override var name: String = "Movhide"
override var mainUrl: String = "https://movhide.pro"
}
class Ztreamhub : Filesim() {
override val mainUrl: String = "https://ztreamhub.com" //Here 'cause works
override val name = "Zstreamhub"
}
class FileMoon : Filesim() {
override val mainUrl = "https://filemoon.to"
override val name = "FileMoon"
}
class FileMoonSx : Filesim() {
override val mainUrl = "https://filemoon.sx"
override val name = "FileMoonSx"
}
open class Filesim : ExtractorApi() {
override val name = "Filesim"
override val mainUrl = "https://files.im"
override val requiresReferer = false
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val sources = mutableListOf<ExtractorLink>()
with(app.get(url).document) {
this.select("script").map { script ->
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
val data = getAndUnpack(script.data()).substringAfter("sources:[").substringBefore("]")
tryParseJson<List<ResponseSource>>("[$data]")?.map {
M3u8Helper.generateM3u8(
name,
it.file,
"$mainUrl/",
).forEach { m3uData -> sources.add(m3uData) }
}
}
}
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val response = app.get(url, referer = referer)
val script = if (!getPacked(response.text).isNullOrEmpty()) {
getAndUnpack(response.text)
} else {
response.document.selectFirst("script:containsData(sources:)")?.data()
}
return sources
val m3u8 =
Regex("file:\\s*\"(.*?m3u8.*?)\"").find(script ?: return)?.groupValues?.getOrNull(1)
generateM3u8(
name,
m3u8 ?: return,
mainUrl
).forEach(callback)
}
private data class ResponseSource(
@JsonProperty("file") val file: String,
@JsonProperty("type") val type: String?,
@JsonProperty("label") val label: String?
)
}

View File

@ -2,14 +2,10 @@ package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
import java.security.DigestException
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
class DatabaseGdrive2 : Gdriveplayer() {
override var mainUrl = "https://databasegdriveplayer.co"
@ -65,78 +61,6 @@ open class Gdriveplayer : ExtractorApi() {
?.data()?.let { getAndUnpack(it) }
}
private fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
// https://stackoverflow.com/a/41434590/8166854
private fun GenerateKeyAndIv(
password: ByteArray,
salt: ByteArray,
hashAlgorithm: String = "MD5",
keyLength: Int = 32,
ivLength: Int = 16,
iterations: Int = 1
): List<ByteArray>? {
val md = MessageDigest.getInstance(hashAlgorithm)
val digestLength = md.digestLength
val targetKeySize = keyLength + ivLength
val requiredLength = (targetKeySize + digestLength - 1) / digestLength * digestLength
val generatedData = ByteArray(requiredLength)
var generatedLength = 0
try {
md.reset()
while (generatedLength < targetKeySize) {
if (generatedLength > 0)
md.update(
generatedData,
generatedLength - digestLength,
digestLength
)
md.update(password)
md.update(salt, 0, 8)
md.digest(generatedData, generatedLength, digestLength)
for (i in 1 until iterations) {
md.update(generatedData, generatedLength, digestLength)
md.digest(generatedData, generatedLength, digestLength)
}
generatedLength += digestLength
}
return listOf(
generatedData.copyOfRange(0, keyLength),
generatedData.copyOfRange(keyLength, targetKeySize)
)
} catch (e: DigestException) {
return null
}
}
private fun cryptoAESHandler(
data: AesData,
pass: ByteArray,
encrypt: Boolean = true
): String? {
val (key, iv) = GenerateKeyAndIv(pass, data.s.decodeHex()) ?: return null
val cipher = Cipher.getInstance("AES/CBC/NoPadding")
return if (!encrypt) {
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
String(cipher.doFinal(base64DecodeArray(data.ct)))
} else {
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
base64Encode(cipher.doFinal(data.ct.toByteArray()))
}
}
private fun Regex.first(str: String): String? {
return find(str)?.groupValues?.getOrNull(1)
}
@ -154,14 +78,14 @@ open class Gdriveplayer : ExtractorApi() {
val document = app.get(url).document
val eval = unpackJs(document)?.replace("\\", "") ?: return
val data = tryParseJson<AesData>(Regex("data='(\\S+?)'").first(eval)) ?: return
val data = Regex("data='(\\S+?)'").first(eval) ?: return
val password = Regex("null,['|\"](\\w+)['|\"]").first(eval)
?.split(Regex("\\D+"))
?.joinToString("") {
Char(it.toInt()).toString()
}.let { Regex("var pass = \"(\\S+?)\"").first(it ?: return)?.toByteArray() }
?: throw ErrorLoadingException("can't find password")
val decryptedData = cryptoAESHandler(data, password, false)?.let { getAndUnpack(it) }?.replace("\\", "")
val decryptedData = cryptoAESHandler(data, password, false, "AES/CBC/NoPadding")?.let { getAndUnpack(it) }?.replace("\\", "")
val sourceData = decryptedData?.substringAfter("sources:[")?.substringBefore("],")
val subData = decryptedData?.substringAfter("tracks:[")?.substringBefore("],")
@ -194,12 +118,6 @@ open class Gdriveplayer : ExtractorApi() {
}
data class AesData(
@JsonProperty("ct") val ct: String,
@JsonProperty("iv") val iv: String,
@JsonProperty("s") val s: String
)
data class Tracks(
@JsonProperty("file") val file: String,
@JsonProperty("kind") val kind: String,

View File

@ -0,0 +1,62 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class Gofile : ExtractorApi() {
override val name = "Gofile"
override val mainUrl = "https://gofile.io"
override val requiresReferer = false
private val mainApi = "https://api.gofile.io"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = Regex("/(?:\\?c=|d/)([\\da-zA-Z-]+)").find(url)?.groupValues?.get(1)
val token = app.get("$mainApi/createAccount").parsedSafe<Account>()?.data?.get("token")
val websiteToken = app.get("$mainUrl/dist/js/alljs.js").text.let {
Regex("fetchData.wt\\s*=\\s*\"([^\"]+)").find(it)?.groupValues?.get(1)
}
app.get("$mainApi/getContent?contentId=$id&token=$token&wt=$websiteToken")
.parsedSafe<Source>()?.data?.contents?.forEach {
callback.invoke(
ExtractorLink(
this.name,
this.name,
it.value["link"] ?: return,
"",
getQuality(it.value["name"]),
headers = mapOf(
"Cookie" to "accountToken=$token"
)
)
)
}
}
private fun getQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
data class Account(
@JsonProperty("data") val data: HashMap<String, String>? = null,
)
data class Data(
@JsonProperty("contents") val contents: HashMap<String, HashMap<String, String>>? = null,
)
data class Source(
@JsonProperty("data") val data: Data? = null,
)
}

View File

@ -6,6 +6,11 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
class Vanfem : GuardareStream() {
override var name = "Vanfem"
override var mainUrl = "https://vanfem.com/"
}
class CineGrabber : GuardareStream() {
override var name = "CineGrabber"
override var mainUrl = "https://cinegrabber.com"
@ -53,7 +58,7 @@ open class GuardareStream : ExtractorApi() {
jsonVideoData.data.forEach {
callback.invoke(
ExtractorLink(
it.file + ".${it.type}",
this.name,
this.name,
it.file + ".${it.type}",
mainUrl,

View File

@ -0,0 +1,71 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.extractors.helper.AesHelper
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
open class HDMomPlayer : ExtractorApi() {
override val name = "HDMomPlayer"
override val mainUrl = "https://hdmomplayer.com"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val m3u_link:String?
val ext_ref = referer ?: ""
val i_source = app.get(url, referer=ext_ref).text
val bePlayer = Regex("""bePlayer\('([^']+)',\s*'(\{[^\}]+\})'\);""").find(i_source)?.groupValues
if (bePlayer != null) {
val bePlayerPass = bePlayer.get(1)
val bePlayerData = bePlayer.get(2)
val encrypted = AesHelper.cryptoAESHandler(bePlayerData, bePlayerPass.toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
Log.d("Kekik_${this.name}", "encrypted » ${encrypted}")
m3u_link = Regex("""video_location\":\"([^\"]+)""").find(encrypted)?.groupValues?.get(1)
} else {
m3u_link = Regex("""file:\"([^\"]+)""").find(i_source)?.groupValues?.get(1)
val track_str = Regex("""tracks:\[([^\]]+)""").find(i_source)?.groupValues?.get(1)
if (track_str != null) {
val tracks:List<Track> = jacksonObjectMapper().readValue("[${track_str}]")
for (track in tracks) {
if (track.file == null || track.label == null) continue
if (track.label.contains("Forced")) continue
subtitleCallback.invoke(
SubtitleFile(
lang = track.label,
url = fixUrl(mainUrl + track.file)
)
)
}
}
}
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = m3u_link ?: throw ErrorLoadingException("m3u link not found"),
referer = url,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
data class Track(
@JsonProperty("file") val file: String?,
@JsonProperty("label") val label: String?,
@JsonProperty("kind") val kind: String?,
@JsonProperty("language") val language: String?,
@JsonProperty("default") val default: String?
)
}

View File

@ -0,0 +1,59 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class HDPlayerSystem : ExtractorApi() {
override val name = "HDPlayerSystem"
override val mainUrl = "https://hdplayersystem.live"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val vid_id = if (url.contains("video/")) {
url.substringAfter("video/")
} else {
url.substringAfter("?data=")
}
val post_url = "${mainUrl}/player/index.php?data=${vid_id}&do=getVideo"
Log.d("Kekik_${this.name}", "post_url » ${post_url}")
val response = app.post(
post_url,
data = mapOf(
"hash" to vid_id,
"r" to ext_ref
),
referer = ext_ref,
headers = mapOf(
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With" to "XMLHttpRequest"
)
)
val video_response = response.parsedSafe<SystemResponse>() ?: throw ErrorLoadingException("failed to parse response")
val m3u_link = video_response.securedLink
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = m3u_link,
referer = ext_ref,
quality = Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
data class SystemResponse(
@JsonProperty("hls") val hls: String,
@JsonProperty("videoImage") val videoImage: String? = null,
@JsonProperty("videoSource") val videoSource: String,
@JsonProperty("securedLink") val securedLink: String
)
}

View File

@ -0,0 +1,8 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
class HDStreamAble : PeaceMakerst() {
override var name = "HDStreamAble"
override var mainUrl = "https://hdstreamable.com"
}

View File

@ -0,0 +1,23 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
class Hotlinger : ContentX() {
override var name = "Hotlinger"
override var mainUrl = "https://hotlinger.com"
}
class FourCX : ContentX() {
override var name = "FourCX"
override var mainUrl = "https://four.contentx.me"
}
class PlayRu : ContentX() {
override var name = "PlayRu"
override var mainUrl = "https://playru.net"
}
class FourPlayRu : ContentX() {
override var name = "FourPlayRu"
override var mainUrl = "https://four.playru.net"
}

View File

@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
class Neonime7n : Hxfile() {
override val name = "Neonime7n"
override val mainUrl = "https://7njctn.neonime.watch"
override val mainUrl = "https://neonime.fun"
override val redirect = false
}
@ -19,7 +19,7 @@ class Neonime8n : Hxfile() {
class KotakAnimeid : Hxfile() {
override val name = "KotakAnimeid"
override val mainUrl = "https://kotakanimeid.com"
override val mainUrl = "https://nontonanimeid.bio"
override val requiresReferer = true
}
@ -97,4 +97,4 @@ open class Hxfile : ExtractorApi() {
@JsonProperty("label") val label: String?
)
}
}

View File

@ -0,0 +1,37 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.httpsify
open class Krakenfiles : ExtractorApi() {
override val name = "Krakenfiles"
override val mainUrl = "https://krakenfiles.com"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = Regex("/(?:view|embed-video)/([\\da-zA-Z]+)").find(url)?.groupValues?.get(1)
val doc = app.get("$mainUrl/embed-video/$id").document
val link = doc.selectFirst("source")?.attr("src")
callback.invoke(
ExtractorLink(
this.name,
this.name,
httpsify(link ?: return),
"",
Qualities.Unknown.value
)
)
}
}

View File

@ -18,31 +18,38 @@ open class Linkbox : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = Regex("""(/file/|id=)(\S+)[&/?]""").find(url)?.groupValues?.get(2)
app.get("$mainUrl/api/open/get_url?itemId=$id", referer=url).parsedSafe<Responses>()?.data?.rList?.map { link ->
callback.invoke(
ExtractorLink(
name,
name,
link.url,
url,
getQualityFromName(link.resolution)
val token = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1)
val id = app.get("$mainUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token").parsedSafe<Responses>()?.data?.itemId
app.get("$mainUrl/api/file/detail?itemId=$id", referer = url)
.parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->
callback.invoke(
ExtractorLink(
name,
name,
link.url ?: return@map null,
url,
getQualityFromName(link.resolution)
)
)
)
}
}
}
data class RList(
@JsonProperty("url") val url: String,
@JsonProperty("resolution") val resolution: String?,
data class Resolutions(
@JsonProperty("url") val url: String? = null,
@JsonProperty("resolution") val resolution: String? = null,
)
data class ItemInfo(
@JsonProperty("resolutionList") val resolutionList: ArrayList<Resolutions>? = arrayListOf(),
)
data class Data(
@JsonProperty("rList") val rList: List<RList>?,
@JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
@JsonProperty("itemId") val itemId: String? = null,
)
data class Responses(
@JsonProperty("data") val data: Data?,
@JsonProperty("data") val data: Data? = null,
)
}

View File

@ -0,0 +1,54 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class MailRu : ExtractorApi() {
override val name = "MailRu"
override val mainUrl = "https://my.mail.ru"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
Log.d("Kekik_${this.name}", "url » ${url}")
val vid_id = url.substringAfter("video/embed/").trim()
val video_req = app.get("${mainUrl}/+/video/meta/${vid_id}", referer=url)
val video_key = video_req.cookies["video_key"].toString()
Log.d("Kekik_${this.name}", "video_key » ${video_key}")
val video_data = AppUtils.tryParseJson<MailRuData>(video_req.text) ?: throw ErrorLoadingException("Video not found")
for (video in video_data.videos) {
Log.d("Kekik_${this.name}", "video » ${video}")
val video_url = if (video.url.startsWith("//")) "https:${video.url}" else video.url
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = video_url,
referer = url,
headers = mapOf("Cookie" to "video_key=${video_key}"),
quality = getQualityFromName(video.key),
isM3u8 = false
)
)
}
}
data class MailRuData(
@JsonProperty("provider") val provider: String,
@JsonProperty("videos") val videos: List<MailRuVideoData>
)
data class MailRuVideoData(
@JsonProperty("url") val url: String,
@JsonProperty("key") val key: String
)
}

View File

@ -0,0 +1,43 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
open class Mediafire : ExtractorApi() {
override val name = "Mediafire"
override val mainUrl = "https://www.mediafire.com"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url, referer = referer).document
val title = res.select("div.dl-btn-label").text()
val video = res.selectFirst("a#downloadButton")?.attr("href")
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"",
getQuality(title),
INFER_TYPE
)
)
}
private fun getQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}

View File

@ -7,14 +7,12 @@ import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
class SpeedoStream1 : SpeedoStream() {
override val mainUrl = "https://speedostream.nl"
}
open class Minoplres : ExtractorApi() {
open class SpeedoStream : ExtractorApi() {
override val name = "SpeedoStream"
override val mainUrl = "https://speedostream.com"
override val name = "Minoplres" // formerly SpeedoStream
override val requiresReferer = true
override val mainUrl = "https://minoplres.xyz" // formerly speedostream.bond
private val hostUrl = "https://minoplres.xyz"
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val sources = mutableListOf<ExtractorLink>()
@ -26,7 +24,7 @@ open class SpeedoStream : ExtractorApi() {
M3u8Helper.generateM3u8(
name,
it.file,
"$mainUrl/",
"$hostUrl/",
).forEach { m3uData -> sources.add(m3uData) }
}
}
@ -37,6 +35,4 @@ open class SpeedoStream : ExtractorApi() {
private data class File(
@JsonProperty("file") val file: String,
)
}
}

View File

@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
class MoviehabNet : Moviehab() {
override var mainUrl = "https://play.moviehab.net"
override var mainUrl = "https://play.moviehab.asia"
}
open class Moviehab : ExtractorApi() {
@ -41,4 +41,4 @@ open class Moviehab : ExtractorApi() {
}
}
}
}
}

View File

@ -10,24 +10,39 @@ open class Mp4Upload : ExtractorApi() {
override var name = "Mp4Upload"
override var mainUrl = "https://www.mp4upload.com"
private val srcRegex = Regex("""player\.src\("(.*?)"""")
override val requiresReferer = true
private val srcRegex2 = Regex("""player\.src\([\w\W]*src: "(.*?)"""")
override val requiresReferer = true
private val idMatch = Regex("""mp4upload\.com/(embed-|)([A-Za-z0-9]*)""")
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
with(app.get(url)) {
getAndUnpack(this.text).let { unpackedText ->
val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
return listOf(
ExtractorLink(
name,
name,
link,
url,
quality ?: Qualities.Unknown.value,
)
)
}
}
val realUrl = idMatch.find(url)?.groupValues?.get(2)?.let { id ->
"$mainUrl/embed-$id.html"
} ?: url
val response = app.get(realUrl)
val unpackedText = getAndUnpack(response.text)
val quality =
unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
return listOf(
ExtractorLink(
name,
name,
link,
url,
quality ?: Qualities.Unknown.value,
)
)
}
srcRegex2.find(unpackedText)?.groupValues?.get(1)?.let { link ->
return listOf(
ExtractorLink(
name,
name,
link,
url,
quality ?: Qualities.Unknown.value,
)
)
}
return null
}

View File

@ -9,7 +9,7 @@ import java.net.URI
open class MultiQuality : ExtractorApi() {
override var name = "MultiQuality"
override var mainUrl = "https://gogo-play.net"
override var mainUrl = "https://anihdplay.com"
private val sourceRegex = Regex("""file:\s*['"](.*?)['"],label:\s*['"](.*?)['"]""")
private val m3u8Regex = Regex(""".*?(\d*).m3u8""")
private val urlRegex = Regex("""(.*?)([^/]+$)""")
@ -56,4 +56,4 @@ open class MultiQuality : ExtractorApi() {
return extractedLinksList
}
}
}
}

View File

@ -0,0 +1,61 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class Odnoklassniki : ExtractorApi() {
override val name = "Odnoklassniki"
override val mainUrl = "https://odnoklassniki.ru"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
Log.d("Kekik_${this.name}", "url » ${url}")
val user_agent = mapOf("User-Agent" to "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36")
val video_req = app.get(url, headers=user_agent).text.replace("\\&quot;", "\"").replace("\\\\", "\\")
.replace(Regex("\\\\u([0-9A-Fa-f]{4})")) { matchResult ->
Integer.parseInt(matchResult.groupValues[1], 16).toChar().toString()
}
val videos_str = Regex("""\"videos\":(\[[^\]]*\])""").find(video_req)?.groupValues?.get(1) ?: throw ErrorLoadingException("Video not found")
val videos = AppUtils.tryParseJson<List<OkRuVideo>>(videos_str) ?: throw ErrorLoadingException("Video not found")
for (video in videos) {
Log.d("Kekik_${this.name}", "video » ${video}")
val video_url = if (video.url.startsWith("//")) "https:${video.url}" else video.url
val quality = video.name.uppercase()
.replace("MOBILE", "144p")
.replace("LOWEST", "240p")
.replace("LOW", "360p")
.replace("SD", "480p")
.replace("HD", "720p")
.replace("FULL", "1080p")
.replace("QUAD", "1440p")
.replace("ULTRA", "4k")
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = video_url,
referer = url,
quality = getQualityFromName(quality),
headers = user_agent,
isM3u8 = false
)
)
}
}
data class OkRuVideo(
@JsonProperty("name") val name: String,
@JsonProperty("url") val url: String,
)
}

View File

@ -1,67 +1,13 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
data class DataOptionsJson (
@JsonProperty("flashvars") var flashvars : Flashvars? = Flashvars(),
)
data class Flashvars (
@JsonProperty("metadata") var metadata : String? = null,
@JsonProperty("hlsManifestUrl") var hlsManifestUrl : String? = null, //m3u8
)
data class MetadataOkru (
@JsonProperty("videos") var videos: ArrayList<Videos> = arrayListOf(),
)
data class Videos (
@JsonProperty("name") var name : String,
@JsonProperty("url") var url : String,
@JsonProperty("seekSchema") var seekSchema : Int? = null,
@JsonProperty("disallowed") var disallowed : Boolean? = null
)
class OkRuHttps: OkRu(){
class OkRuSSL : Odnoklassniki() {
override var name = "OkRuSSL"
override var mainUrl = "https://ok.ru"
}
open class OkRu : ExtractorApi() {
override var name = "Okru"
class OkRuHTTP : Odnoklassniki() {
override var name = "OkRuHTTP"
override var mainUrl = "http://ok.ru"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val doc = app.get(url).document
val sources = ArrayList<ExtractorLink>()
val datajson = doc.select("div[data-options]").attr("data-options")
if (datajson.isNotBlank()) {
val main = parseJson<DataOptionsJson>(datajson)
val metadatajson = parseJson<MetadataOkru>(main.flashvars?.metadata!!)
val servers = metadatajson.videos
servers.forEach {
val quality = it.name.uppercase()
.replace("MOBILE","144p")
.replace("LOWEST","240p")
.replace("LOW","360p")
.replace("SD","480p")
.replace("HD","720p")
.replace("FULL","1080p")
.replace("QUAD","1440p")
.replace("ULTRA","4k")
val extractedurl = it.url.replace("\\\\u0026", "&")
sources.add(ExtractorLink(
name,
name = this.name,
extractedurl,
url,
getQualityFromName(quality),
isM3u8 = false
))
}
}
return sources
}
}
}

View File

@ -0,0 +1,89 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class PeaceMakerst : ExtractorApi() {
override val name = "PeaceMakerst"
override val mainUrl = "https://peacemakerst.com"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val m3u_link:String?
val ext_ref = referer ?: ""
val post_url = "${url}?do=getVideo"
Log.d("Kekik_${this.name}", "post_url » ${post_url}")
val response = app.post(
post_url,
data = mapOf(
"hash" to url.substringAfter("video/"),
"r" to ext_ref,
"s" to ""
),
referer = ext_ref,
headers = mapOf(
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With" to "XMLHttpRequest"
)
)
if (response.text.contains("teve2.com.tr\\/embed\\/")) {
val teve2_id = response.text.substringAfter("teve2.com.tr\\/embed\\/").substringBefore("\"")
val teve2_response = app.get(
"https://www.teve2.com.tr/action/media/${teve2_id}",
referer = "https://www.teve2.com.tr/embed/${teve2_id}"
).parsedSafe<Teve2ApiResponse>() ?: throw ErrorLoadingException("teve2 response is null")
m3u_link = teve2_response.media.link.serviceUrl + "//" + teve2_response.media.link.securePath
} else {
val video_response = response.parsedSafe<PeaceResponse>() ?: throw ErrorLoadingException("peace response is null")
val video_sources = video_response.videoSources
if (video_sources.isNotEmpty()) {
m3u_link = video_sources.lastOrNull()?.file
} else {
m3u_link = null
}
}
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = m3u_link ?: throw ErrorLoadingException("m3u link not found"),
referer = ext_ref,
quality = Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
data class PeaceResponse(
@JsonProperty("videoImage") val videoImage: String?,
@JsonProperty("videoSources") val videoSources: List<VideoSource>,
@JsonProperty("sIndex") val sIndex: String,
@JsonProperty("sourceList") val sourceList: Map<String, String>
)
data class VideoSource(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String,
@JsonProperty("type") val type: String
)
data class Teve2ApiResponse(
@JsonProperty("Media") val media: Teve2Media
)
data class Teve2Media(
@JsonProperty("Link") val link: Teve2Link
)
data class Teve2Link(
@JsonProperty("ServiceUrl") val serviceUrl: String,
@JsonProperty("SecurePath") val securePath: String
)
}

View File

@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.amap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.extractorApis
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
@ -66,7 +67,7 @@ open class Pelisplus(val mainUrl: String) {
href,
page.url,
getQualityFromName(qual),
element.attr("href").contains(".m3u8")
type = INFER_TYPE
)
)
}

View File

@ -0,0 +1,25 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class PixelDrain : ExtractorApi() {
override val name = "PixelDrain"
override val mainUrl = "https://pixeldrain.com"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val mId = Regex("/([ul]/[\\da-zA-Z\\-]+)(?:\\?download)?").find(url)?.groupValues?.get(1)?.split("/")
callback.invoke(
ExtractorLink(
this.name,
this.name,
"$mainUrl/api/file/${mId?.last() ?: return}?download",
url,
Qualities.Unknown.value,
)
)
}
}

View File

@ -0,0 +1,199 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64DecodeArray
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
class Megacloud : Rabbitstream() {
override val name = "Megacloud"
override val mainUrl = "https://megacloud.tv"
override val embed = "embed-2/ajax/e-1"
private val scriptUrl = "$mainUrl/js/player/a/prod/e1-player.min.js"
override suspend fun extractRealKey(sources: String): Pair<String, String> {
val rawKeys = getKeys()
val sourcesArray = sources.toCharArray()
var extractedKey = ""
var currentIndex = 0
for (index in rawKeys) {
val start = index[0] + currentIndex
val end = start + index[1]
for (i in start until end) {
extractedKey += sourcesArray[i].toString()
sourcesArray[i] = ' '
}
currentIndex += index[1]
}
return extractedKey to sourcesArray.joinToString("").replace(" ", "")
}
private suspend fun getKeys(): List<List<Int>> {
val script = app.get(scriptUrl).text
fun matchingKey(value: String): String {
return Regex(",$value=((?:0x)?([0-9a-fA-F]+))").find(script)?.groupValues?.get(1)
?.removePrefix("0x") ?: throw ErrorLoadingException("Failed to match the key")
}
val regex = Regex("case\\s*0x[0-9a-f]+:(?![^;]*=partKey)\\s*\\w+\\s*=\\s*(\\w+)\\s*,\\s*\\w+\\s*=\\s*(\\w+);")
val indexPairs = regex.findAll(script).toList().map { match ->
val matchKey1 = matchingKey(match.groupValues[1])
val matchKey2 = matchingKey(match.groupValues[2])
try {
listOf(matchKey1.toInt(16), matchKey2.toInt(16))
} catch (e: NumberFormatException) {
emptyList()
}
}.filter { it.isNotEmpty() }
return indexPairs
}
}
class Dokicloud : Rabbitstream() {
override val name = "Dokicloud"
override val mainUrl = "https://dokicloud.one"
}
// Code found in https://github.com/eatmynerds/key
// special credits to @eatmynerds for providing key
open class Rabbitstream : ExtractorApi() {
override val name = "Rabbitstream"
override val mainUrl = "https://rabbitstream.net"
override val requiresReferer = false
open val embed = "ajax/embed-4"
open val key = "https://raw.githubusercontent.com/eatmynerds/key/e4/key.txt"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = url.substringAfterLast("/").substringBefore("?")
val response = app.get(
"$mainUrl/$embed/getSources?id=$id",
referer = mainUrl,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
)
val encryptedMap = response.parsedSafe<SourcesEncrypted>()
val sources = encryptedMap?.sources
val decryptedSources = if (sources == null || encryptedMap.encrypted == false) {
response.parsedSafe()
} else {
val (key, encData) = extractRealKey(sources)
val decrypted = decryptMapped<List<Sources>>(encData, key)
SourcesResponses(
sources = decrypted,
tracks = encryptedMap.tracks
)
}
decryptedSources?.sources?.map { source ->
M3u8Helper.generateM3u8(
name,
source?.file ?: return@map,
"$mainUrl/",
).forEach(callback)
}
decryptedSources?.tracks?.map { track ->
subtitleCallback.invoke(
SubtitleFile(
track?.label ?: return@map,
track.file ?: return@map
)
)
}
}
open suspend fun extractRealKey(sources: String): Pair<String, String> {
val rawKeys = parseJson<List<Int>>(app.get(key).text)
val extractedKey = base64Encode(rawKeys.map { it.toByte() }.toByteArray())
return extractedKey to sources
}
private inline fun <reified T> decryptMapped(input: String, key: String): T? {
val decrypt = decrypt(input, key)
return AppUtils.tryParseJson(decrypt)
}
private fun decrypt(input: String, key: String): String {
return decryptSourceUrl(
generateKey(
base64DecodeArray(input).copyOfRange(8, 16),
key.toByteArray()
), input
)
}
private fun generateKey(salt: ByteArray, secret: ByteArray): ByteArray {
var key = md5(secret + salt)
var currentKey = key
while (currentKey.size < 48) {
key = md5(key + secret + salt)
currentKey += key
}
return currentKey
}
private fun md5(input: ByteArray): ByteArray {
return MessageDigest.getInstance("MD5").digest(input)
}
private fun decryptSourceUrl(decryptionKey: ByteArray, sourceUrl: String): String {
val cipherData = base64DecodeArray(sourceUrl)
val encrypted = cipherData.copyOfRange(16, cipherData.size)
val aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding")
aesCBC.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(decryptionKey.copyOfRange(0, 32), "AES"),
IvParameterSpec(decryptionKey.copyOfRange(32, decryptionKey.size))
)
val decryptedData = aesCBC?.doFinal(encrypted) ?: throw ErrorLoadingException("Cipher not found")
return String(decryptedData, StandardCharsets.UTF_8)
}
data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null,
)
data class Sources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("label") val label: String? = null,
)
data class SourcesResponses(
@JsonProperty("sources") val sources: List<Sources?>? = emptyList(),
@JsonProperty("tracks") val tracks: List<Tracks?>? = emptyList(),
)
data class SourcesEncrypted(
@JsonProperty("sources") val sources: String? = null,
@JsonProperty("encrypted") val encrypted: Boolean? = null,
@JsonProperty("tracks") val tracks: List<Tracks?>? = emptyList(),
)
}

View File

@ -0,0 +1,50 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class RapidVid : ExtractorApi() {
override val name = "RapidVid"
override val mainUrl = "https://rapidvid.net"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val video_req = app.get(url, referer=ext_ref).text
val sub_urls = mutableSetOf<String>()
Regex("""captions\",\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(video_req).forEach {
val (sub_url, sub_lang) = it.destructured
if (sub_url in sub_urls) { return@forEach }
sub_urls.add(sub_url)
subtitleCallback.invoke(
SubtitleFile(
lang = sub_lang.replace("\\u0131", "ı").replace("\\u0130", "İ").replace("\\u00fc", "ü").replace("\\u00e7", "ç"),
url = fixUrl(sub_url.replace("\\", ""))
)
)
}
val extracted_value = Regex("""file": "(.*)",""").find(video_req)?.groupValues?.get(1) ?: throw ErrorLoadingException("File not found")
val bytes = extracted_value.split("\\x").filter { it.isNotEmpty() }.map { it.toInt(16).toByte() }.toByteArray()
val decoded = String(bytes, Charsets.UTF_8)
Log.d("Kekik_${this.name}", "decoded » ${decoded}")
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = decoded,
referer = ext_ref,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
}

View File

@ -0,0 +1,28 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
open class Sendvid : ExtractorApi() {
override var name = "Sendvid"
override val mainUrl = "https://sendvid.com"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val doc = app.get(url).document
val urlString = doc.select("head meta[property=og:video:secure_url]").attr("content")
if (urlString.contains("m3u8")) {
generateM3u8(
name,
urlString,
mainUrl,
).forEach(callback)
}
}
}

View File

@ -0,0 +1,33 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class SibNet : ExtractorApi() {
override val name = "SibNet"
override val mainUrl = "https://video.sibnet.ru"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val i_source = app.get(url, referer=ext_ref).text
var m3u_link = Regex("""player.src\(\[\{src: \"([^\"]+)""").find(i_source)?.groupValues?.get(1) ?: throw ErrorLoadingException("m3u link not found")
m3u_link = "${mainUrl}${m3u_link}"
Log.d("Kekik_${this.name}", "m3u_link » ${m3u_link}")
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = m3u_link,
referer = url,
quality = Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
}

View File

@ -6,6 +6,51 @@ import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import kotlin.random.Random
class Sblona : StreamSB() {
override var name = "Sblona"
override var mainUrl = "https://sblona.com"
}
class Lvturbo : StreamSB() {
override var name = "Lvturbo"
override var mainUrl = "https://lvturbo.com"
}
class Sbrapid : StreamSB() {
override var name = "Sbrapid"
override var mainUrl = "https://sbrapid.com"
}
class Sbface : StreamSB() {
override var name = "Sbface"
override var mainUrl = "https://sbface.com"
}
class Sbsonic : StreamSB() {
override var name = "Sbsonic"
override var mainUrl = "https://sbsonic.com"
}
class Vidgomunimesb : StreamSB() {
override var mainUrl = "https://vidgomunimesb.xyz"
}
class Sbasian : StreamSB() {
override var mainUrl = "https://sbasian.pro"
override var name = "Sbasian"
}
class Sbnet : StreamSB() {
override var name = "Sbnet"
override var mainUrl = "https://sbnet.one"
}
class Keephealth : StreamSB() {
override var name = "Keephealth"
override var mainUrl = "https://keephealth.info"
}
class Sbspeed : StreamSB() {
override var name = "Sbspeed"
@ -77,24 +122,70 @@ class StreamSB10 : StreamSB() {
override var mainUrl = "https://sbplay2.xyz"
}
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
class StreamSB11 : StreamSB() {
override var mainUrl = "https://sbbrisk.com"
}
class Sblongvu : StreamSB() {
override var mainUrl = "https://sblongvu.com"
}
open class StreamSB : ExtractorApi() {
override var name = "StreamSB"
override var mainUrl = "https://watchsb.com"
override val requiresReferer = false
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
private val hexArray = "0123456789ABCDEF".toCharArray()
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val regexID =
Regex("(embed-[a-zA-Z\\d]{0,8}[a-zA-Z\\d_-]+|/e/[a-zA-Z\\d]{0,8}[a-zA-Z\\d_-]+)")
val id = regexID.findAll(url).map {
it.value.replace(Regex("(embed-|/e/)"), "")
}.first()
val master = "$mainUrl/375664356a494546326c4b797c7c6e756577776778623171737/${encodeId(id)}"
val headers = mapOf(
"watchsb" to "sbstream",
)
val mapped = app.get(
master.lowercase(),
headers = headers,
referer = url,
).parsedSafe<Main>()
M3u8Helper.generateM3u8(
name,
mapped?.streamData?.file ?: return,
url,
headers = headers
).forEach(callback)
private fun bytesToHex(bytes: ByteArray): String {
val hexChars = CharArray(bytes.size * 2)
for (j in bytes.indices) {
val v = bytes[j].toInt() and 0xFF
hexChars[j * 2] = hexArray[v ushr 4]
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
mapped.streamData.subs?.map {sub ->
subtitleCallback.invoke(
SubtitleFile(
sub.label.toString(),
sub.file ?: return@map null,
)
)
}
}
private fun encodeId(id: String): String {
val code = "${createHashTable()}||$id||${createHashTable()}||streamsb"
return code.toCharArray().joinToString("") { char ->
char.code.toString(16)
}
}
private fun createHashTable(): String {
return buildString {
repeat(12) {
append(alphabet[Random.nextInt(alphabet.length)])
}
}
return String(hexChars)
}
data class Subs (
@ -118,42 +209,4 @@ open class StreamSB : ExtractorApi() {
@JsonProperty("status_code") val statusCode: Int,
)
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val regexID =
Regex("(embed-[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+|/e/[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
val id = regexID.findAll(url).map {
it.value.replace(Regex("(embed-|/e/)"), "")
}.first()
// val master = "$mainUrl/sources48/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362"
val master = "$mainUrl/sources50/" + bytesToHex("||$id||||streamsb".toByteArray()) + "/"
val headers = mapOf(
"watchsb" to "sbstream",
)
val mapped = app.get(
master.lowercase(),
headers = headers,
referer = url,
).parsedSafe<Main>()
// val urlmain = mapped.streamData.file.substringBefore("/hls/")
M3u8Helper.generateM3u8(
name,
mapped?.streamData?.file ?: return,
url,
headers = headers
).forEach(callback)
mapped.streamData.subs?.map {sub ->
subtitleCallback.invoke(
SubtitleFile(
sub.label.toString(),
sub.file ?: return@map null,
)
)
}
}
}
}

View File

@ -9,6 +9,10 @@ class StreamTapeNet : StreamTape() {
override var mainUrl = "https://streamtape.net"
}
class StreamTapeXyz : StreamTape() {
override var mainUrl = "https://streamtape.xyz"
}
class ShaveTape : StreamTape(){
override var mainUrl = "https://shavetape.cash"
}

View File

@ -0,0 +1,34 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class StreamWishExtractor : ExtractorApi() {
override var name = "StreamWish"
override var mainUrl = "https://streamwish.to"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val response = app.get(
url, referer = referer ?: "$mainUrl/", interceptor = WebViewResolver(
Regex("""master\.m3u8""")
)
)
val sources = mutableListOf<ExtractorLink>()
if (response.url.contains("m3u8"))
sources.add(
ExtractorLink(
source = name,
name = name,
url = response.url,
referer = referer ?: "$mainUrl/",
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
return sources
}
}

View File

@ -0,0 +1,42 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getAndUnpack
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.M3u8Helper
open class StreamoUpload : ExtractorApi() {
override val name = "StreamoUpload"
override val mainUrl = "https://streamoupload.xyz"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val sources = mutableListOf<ExtractorLink>()
val response = app.get(url, referer = referer)
val scriptElements = response.document.select("script").map { script ->
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
val data = getAndUnpack(script.data())
.substringAfter("sources:[")
.substringBefore("],")
.replace("file", "\"file\"")
.trim()
tryParseJson<File>(data)?.let {
M3u8Helper.generateM3u8(
name,
it.file,
"$mainUrl/",
).forEach { m3uData -> sources.add(m3uData) }
}
}
}
return sources
}
private data class File(
@JsonProperty("file") val file: String,
)
}

View File

@ -0,0 +1,73 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class TRsTX : ExtractorApi() {
override val name = "TRsTX"
override val mainUrl = "https://trstx.org"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val video_req = app.get(url, referer=ext_ref).text
val file = Regex("""file\":\"([^\"]+)""").find(video_req)?.groupValues?.get(1) ?: throw ErrorLoadingException("File not found")
val postLink = "${mainUrl}/" + file.replace("\\", "")
val rawList = app.post(postLink, referer=ext_ref).parsedSafe<List<Any>>() ?: throw ErrorLoadingException("Post link not found")
val postJson: List<TrstxVideoData> = rawList.drop(1).map { item ->
val mapItem = item as Map<*, *>
TrstxVideoData(
title = mapItem["title"] as? String,
file = mapItem["file"] as? String
)
}
Log.d("Kekik_${this.name}", "postJson » ${postJson}")
val vid_links = mutableSetOf<String>()
val vid_map = mutableListOf<Map<String, String>>()
for (item in postJson) {
if (item.file == null || item.title == null) continue
val fileUrl = "${mainUrl}/playlist/" + item.file.substring(1) + ".txt"
val videoData = app.post(fileUrl, referer=ext_ref).text
if (videoData in vid_links) { continue }
vid_links.add(videoData)
vid_map.add(mapOf(
"title" to item.title,
"videoData" to videoData
))
}
for (mapEntry in vid_map) {
Log.d("Kekik_${this.name}", "mapEntry » ${mapEntry}")
val title = mapEntry["title"] ?: continue
val m3u_link = mapEntry["videoData"] ?: continue
callback.invoke(
ExtractorLink(
source = this.name,
name = "${this.name} - ${title}",
url = m3u_link,
referer = ext_ref,
quality = Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
}
data class TrstxVideoData(
@JsonProperty("title") val title: String? = null,
@JsonProperty("file") val file: String? = null
)
}

View File

@ -30,7 +30,7 @@ open class Tantifilm : ExtractorApi() {
val jsonvideodata = parseJson<TantifilmJsonData>(response)
return jsonvideodata.data.map {
ExtractorLink(
it.file+".${it.type}",
this.name,
this.name,
it.file+".${it.type}",
mainUrl,

View File

@ -0,0 +1,45 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
open class TauVideo : ExtractorApi() {
override val name = "TauVideo"
override val mainUrl = "https://tau-video.xyz"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val video_key = url.split("/").last()
val video_url = "${mainUrl}/api/video/${video_key}"
Log.d("Kekik_${this.name}", "video_url » ${video_url}")
val api = app.get(video_url).parsedSafe<TauVideoUrls>() ?: throw ErrorLoadingException("TauVideo")
for (video in api.urls) {
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = video.url,
referer = ext_ref,
quality = getQualityFromName(video.label),
type = INFER_TYPE
)
)
}
}
data class TauVideoUrls(
@JsonProperty("urls") val urls: List<TauVideoData>
)
data class TauVideoData(
@JsonProperty("url") val url: String,
@JsonProperty("label") val label: String,
)
}

View File

@ -7,6 +7,10 @@ class Uqload1 : Uqload() {
override var mainUrl = "https://uqload.com"
}
class Uqload2 : Uqload() {
override var mainUrl = "https://uqload.co"
}
open class Uqload : ExtractorApi() {
override val name: String = "Uqload"
override val mainUrl: String = "https://www.uqload.com"
@ -15,30 +19,14 @@ open class Uqload : ExtractorApi() {
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val lang = url.substring(0, 2)
val flag =
if (lang == "vo") {
" \uD83C\uDDEC\uD83C\uDDE7"
}
else if (lang == "vf"){
" \uD83C\uDDE8\uD83C\uDDF5"
} else {
""
}
val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
url
} else {
url.substring(2, url.length)
}
with(app.get(cleaned_url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
with(app.get(url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
srcRegex.find(this.text)?.groupValues?.get(1)?.replace("\"", "")?.let { link ->
return listOf(
ExtractorLink(
name,
name + flag,
name,
link,
cleaned_url,
url,
Qualities.Unknown.value,
)
)

View File

@ -0,0 +1,45 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class Userscloud : ExtractorApi() {
override val name = "Userscloud"
override val mainUrl = "https://userscloud.com"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url).document
val video = res.selectFirst("video#vjsplayer source")?.attr("src")
val quality = res.selectFirst("div.innerTB h2 b")?.text()
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"$mainUrl/",
getQuality(quality),
headers = mapOf(
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
"Range" to "bytes=0-",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "no-cors",
)
)
)
}
private fun getQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}

View File

@ -0,0 +1,51 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class Uservideo : ExtractorApi() {
override val name: String = "Uservideo"
override val mainUrl: String = "https://uservideo.xyz"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val script = app.get(url).document.selectFirst("script:containsData(hosts =)")?.data()
val host = script?.substringAfter("hosts = [\"")?.substringBefore("\"];")
val servers = script?.substringAfter("servers = \"")?.substringBefore("\";")
val sources = app.get("$host/s/$servers").text.substringAfter("\"sources\":[").substringBefore("],").let {
AppUtils.tryParseJson<List<Sources>>("[$it]")
}
val quality = Regex("(\\d{3,4})[Pp]").find(url)?.groupValues?.getOrNull(1)?.toIntOrNull()
sources?.map { source ->
callback.invoke(
ExtractorLink(
name,
name,
source.src ?: return@map null,
url,
quality ?: Qualities.Unknown.value,
)
)
}
}
data class Sources(
@JsonProperty("src") val src: String? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("label") val label: String? = null,
)
}

View File

@ -0,0 +1,51 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
open class Vicloud : ExtractorApi() {
override val name: String = "Vicloud"
override val mainUrl: String = "https://vicloud.sbs"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = Regex("\"apiQuery\":\"(.*?)\"").find(app.get(url).text)?.groupValues?.getOrNull(1)
app.get(
"$mainUrl/api/?$id=&_=${System.currentTimeMillis()}",
headers = mapOf(
"X-Requested-With" to "XMLHttpRequest"
),
referer = url
).parsedSafe<Responses>()?.sources?.map { source ->
callback.invoke(
ExtractorLink(
name,
name,
source.file ?: return@map null,
url,
getQualityFromName(source.label),
)
)
}
}
private data class Sources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
)
private data class Responses(
@JsonProperty("sources") val sources: List<Sources>? = arrayListOf(),
)
}

View File

@ -0,0 +1,50 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class VidMoxy : ExtractorApi() {
override val name = "VidMoxy"
override val mainUrl = "https://vidmoxy.com"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val video_req = app.get(url, referer=ext_ref).text
val sub_urls = mutableSetOf<String>()
Regex("""captions\",\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(video_req).forEach {
val (sub_url, sub_lang) = it.destructured
if (sub_url in sub_urls) { return@forEach }
sub_urls.add(sub_url)
subtitleCallback.invoke(
SubtitleFile(
lang = sub_lang.replace("\\u0131", "ı").replace("\\u0130", "İ").replace("\\u00fc", "ü").replace("\\u00e7", "ç"),
url = fixUrl(sub_url.replace("\\", ""))
)
)
}
val extracted_value = Regex("""file": "(.*)",""").find(video_req)?.groupValues?.get(1) ?: throw ErrorLoadingException("File not found")
val bytes = extracted_value.split("\\x").filter { it.isNotEmpty() }.map { it.toInt(16).toByte() }.toByteArray()
val decoded = String(bytes, Charsets.UTF_8)
Log.d("Kekik_${this.name}", "decoded » ${decoded}")
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = decoded,
referer = ext_ref,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
}

View File

@ -59,8 +59,8 @@ open class VidSrcExtractor : ExtractorApi() {
if (datahash.isNotBlank()) {
val links = try {
app.get(
"$absoluteUrl/src/$datahash",
referer = "https://source.vidsrc.me/"
"$absoluteUrl/srcrcp/$datahash",
referer = "https://rcp.vidsrc.me/"
).url
} catch (e: Exception) {
""
@ -71,7 +71,7 @@ open class VidSrcExtractor : ExtractorApi() {
serverslist.amap { server ->
val linkfixed = server.replace("https://vidsrc.xyz/", "https://embedsito.com/")
if (linkfixed.contains("/pro")) {
if (linkfixed.contains("/prorcp")) {
val srcresponse = app.get(server, referer = absoluteUrl).text
val m3u8Regex = Regex("((https:|http:)//.*\\.m3u8)")
val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@amap

View File

@ -0,0 +1,65 @@
package com.lagradost.cloudstream3.extractors
import android.util.Base64
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.amap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import java.net.URLDecoder
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
class VidSrcTo : ExtractorApi() {
override val name = "VidSrcTo"
override val mainUrl = "https://vidsrc.to"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val mediaId = app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") ?: return
val res = app.get("$mainUrl/ajax/embed/episode/$mediaId/sources").parsedSafe<VidsrctoEpisodeSources>() ?: return
if (res.status != 200) return
res.result?.amap { source ->
val embedRes = app.get("$mainUrl/ajax/embed/source/${source.id}").parsedSafe<VidsrctoEmbedSource>() ?: return@amap
val finalUrl = DecryptUrl(embedRes.result.encUrl)
if(finalUrl.equals(embedRes.result.encUrl)) return@amap
when (source.title) {
"Vidplay" -> AnyVidplay(finalUrl.substringBefore("/e/")).getUrl(finalUrl, referer, subtitleCallback, callback)
"Filemoon" -> FileMoon().getUrl(finalUrl, referer, subtitleCallback, callback)
}
}
}
private fun DecryptUrl(encUrl: String): String {
var data = encUrl.toByteArray()
data = Base64.decode(data, Base64.URL_SAFE)
val rc4Key = SecretKeySpec("WXrUARXb1aDLaZjI".toByteArray(), "RC4")
val cipher = Cipher.getInstance("RC4")
cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
data = cipher.doFinal(data)
return URLDecoder.decode(data.toString(Charsets.UTF_8), "utf-8")
}
data class VidsrctoEpisodeSources(
@JsonProperty("status") val status: Int,
@JsonProperty("result") val result: List<VidsrctoResult>?
)
data class VidsrctoResult(
@JsonProperty("id") val id: String,
@JsonProperty("title") val title: String
)
data class VidsrctoEmbedSource(
@JsonProperty("status") val status: Int,
@JsonProperty("result") val result: VidsrctoUrl
)
data class VidsrctoUrl(@JsonProperty("url") val encUrl: String)
}

View File

@ -0,0 +1,72 @@
// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
open class VideoSeyred : ExtractorApi() {
override val name = "VideoSeyred"
override val mainUrl = "https://videoseyred.in"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
val ext_ref = referer ?: ""
val video_id = url.substringAfter("embed/").substringBefore("?")
val video_url = "${mainUrl}/playlist/${video_id}.json"
Log.d("Kekik_${this.name}", "video_url » ${video_url}")
val response_raw = app.get(video_url)
val response_list:List<VideoSeyredSource> = jacksonObjectMapper().readValue(response_raw.text) ?: throw ErrorLoadingException("VideoSeyred")
val response = response_list[0] ?: throw ErrorLoadingException("VideoSeyred")
for (track in response.tracks) {
if (track.label != null && track.kind == "captions") {
subtitleCallback.invoke(
SubtitleFile(
lang = track.label,
url = fixUrl(track.file)
)
)
}
}
for (source in response.sources) {
callback.invoke(
ExtractorLink(
source = this.name,
name = this.name,
url = source.file,
referer = ext_ref,
quality = Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
}
data class VideoSeyredSource(
@JsonProperty("image") val image: String,
@JsonProperty("title") val title: String,
@JsonProperty("sources") val sources: List<VSSource>,
@JsonProperty("tracks") val tracks: List<VSTrack>
)
data class VSSource(
@JsonProperty("file") val file: String,
@JsonProperty("type") val type: String,
@JsonProperty("default") val default: String
)
data class VSTrack(
@JsonProperty("file") val file: String,
@JsonProperty("kind") val kind: String,
@JsonProperty("language") val language: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("default") val default: String? = null
)
}

View File

@ -0,0 +1,101 @@
package com.lagradost.cloudstream3.extractors
import android.util.Log
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
import org.mozilla.javascript.Context
import org.mozilla.javascript.NativeJSON
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.Scriptable
import java.util.Base64
open class Vidguardto : ExtractorApi() {
override val name = "Vidguard"
override val mainUrl = "https://vidguard.to"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url)
val resc = res.document.select("script:containsData(eval)").firstOrNull()?.data()
resc?.let {
val jsonStr2 = AppUtils.parseJson<SvgObject>(runJS2(it))
val watchlink = sigDecode(jsonStr2.stream)
callback.invoke(
ExtractorLink(
this.name,
name,
watchlink,
this.mainUrl,
Qualities.Unknown.value,
INFER_TYPE
)
)
}
}
private fun sigDecode(url: String): String {
val sig = url.split("sig=")[1].split("&")[0]
var t = ""
for (v in sig.chunked(2)) {
val byteValue = Integer.parseInt(v, 16) xor 2
t += byteValue.toChar()
}
val padding = when (t.length % 4) {
2 -> "=="
3 -> "="
else -> ""
}
val decoded = Base64.getDecoder().decode((t + padding).toByteArray(Charsets.UTF_8))
t = String(decoded).dropLast(5).reversed()
val charArray = t.toCharArray()
for (i in 0 until charArray.size - 1 step 2) {
val temp = charArray[i]
charArray[i] = charArray[i + 1]
charArray[i + 1] = temp
}
val modifiedSig = String(charArray).dropLast(5)
return url.replace(sig, modifiedSig)
}
private fun runJS2(hideMyHtmlContent: String): String {
Log.d("runJS", "start")
val rhino = Context.enter()
rhino.initSafeStandardObjects()
rhino.optimizationLevel = -1
val scope: Scriptable = rhino.initSafeStandardObjects()
scope.put("window", scope, scope)
var result = ""
try {
Log.d("runJS", "Executing JavaScript: $hideMyHtmlContent")
rhino.evaluateString(scope, hideMyHtmlContent, "JavaScript", 1, null)
val svgObject = scope.get("svg", scope)
result = if (svgObject is NativeObject) {
NativeJSON.stringify(Context.getCurrentContext(), scope, svgObject, null, null).toString()
} else {
Context.toString(svgObject)
}
Log.d("runJS", "Result: $result")
} catch (e: Exception) {
Log.e("runJS", "Error executing JavaScript", e)
} finally {
Context.exit()
}
return result
}
data class SvgObject(
val stream: String,
val hash: String
)
}

View File

@ -0,0 +1,34 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class VidhideExtractor : ExtractorApi() {
override var name = "VidHide"
override var mainUrl = "https://vidhide.com"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val response = app.get(
url, referer = referer ?: "$mainUrl/", interceptor = WebViewResolver(
Regex("""master\.m3u8""")
)
)
val sources = mutableListOf<ExtractorLink>()
if (response.url.contains("m3u8"))
sources.add(
ExtractorLink(
source = name,
name = name,
url = response.url,
referer = referer ?: "$mainUrl/",
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
return sources
}
}

View File

@ -25,9 +25,13 @@ open class Vidmoly : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val headers = mapOf(
"User-Agent" to "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36",
"Sec-Fetch-Dest" to "iframe"
)
val script = app.get(
url,
headers = headers,
referer = referer,
).document.select("script")
.find { it.data().contains("sources:") }?.data()
@ -66,4 +70,4 @@ open class Vidmoly : ExtractorApi() {
@JsonProperty("kind") val kind: String? = null,
)
}
}

View File

@ -0,0 +1,34 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getAndUnpack
class Vido : ExtractorApi() {
override var name = "Vido"
override var mainUrl = "https://vido.lol"
private val srcRegex = Regex("""sources:\s*\["(.*?)"\]""")
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val methode = app.get(url.replace("/e/", "/embed-")) // fix wiflix and mesfilms
with(methode) {
if (!methode.isSuccessful) return null
//val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
srcRegex.find(this.text)?.groupValues?.get(1)?.let { link ->
return listOf(
ExtractorLink(
name,
name,
link,
url,
Qualities.Unknown.value,
true,
)
)
}
}
return null
}
}

View File

@ -0,0 +1,120 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
// Code found in https://github.com/KillerDogeEmpire/vidplay-keys
// special credits to @KillerDogeEmpire for providing key
class AnyVidplay(hostUrl: String) : Vidplay() {
override val mainUrl = hostUrl
}
class MyCloud : Vidplay() {
override val name = "MyCloud"
override val mainUrl = "https://mcloud.bz"
}
class VidplayOnline : Vidplay() {
override val mainUrl = "https://vidplay.online"
}
open class Vidplay : ExtractorApi() {
override val name = "Vidplay"
override val mainUrl = "https://vidplay.site"
override val requiresReferer = true
open val key =
"https://raw.githubusercontent.com/KillerDogeEmpire/vidplay-keys/keys/keys.json"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = url.substringBefore("?").substringAfterLast("/")
val encodeId = encodeId(id, getKeys())
val mediaUrl = callFutoken(encodeId, url)
val res = app.get(
"$mediaUrl", headers = mapOf(
"Accept" to "application/json, text/javascript, */*; q=0.01",
"X-Requested-With" to "XMLHttpRequest",
), referer = url
).parsedSafe<Response>()?.result
res?.sources?.map {
M3u8Helper.generateM3u8(
this.name,
it.file ?: return@map,
"$mainUrl/"
).forEach(callback)
}
res?.tracks?.filter { it.kind == "captions" }?.map {
subtitleCallback.invoke(
SubtitleFile(it.label ?: return@map, it.file ?: return@map)
)
}
}
private suspend fun getKeys(): List<String> {
return app.get(key).parsed()
}
private suspend fun callFutoken(id: String, url: String): String? {
val script = app.get("$mainUrl/futoken", referer = url).text
val k = "k='(\\S+)'".toRegex().find(script)?.groupValues?.get(1) ?: return null
val a = mutableListOf(k)
for (i in id.indices) {
a.add((k[i % k.length].code + id[i].code).toString())
}
return "$mainUrl/mediainfo/${a.joinToString(",")}?${url.substringAfter("?")}"
}
private fun encodeId(id: String, keyList: List<String>): String {
val cipher1 = Cipher.getInstance("RC4")
val cipher2 = Cipher.getInstance("RC4")
cipher1.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(keyList[0].toByteArray(), "RC4"),
cipher1.parameters
)
cipher2.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(keyList[1].toByteArray(), "RC4"),
cipher2.parameters
)
var input = id.toByteArray()
input = cipher1.doFinal(input)
input = cipher2.doFinal(input)
return base64Encode(input).replace("/", "_")
}
data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null,
)
data class Sources(
@JsonProperty("file") val file: String? = null,
)
data class Result(
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
@JsonProperty("tracks") val tracks: ArrayList<Tracks>? = arrayListOf(),
)
data class Response(
@JsonProperty("result") val result: Result? = null,
)
}

View File

@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.amap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.argamap
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.extractorApis
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
@ -70,7 +71,7 @@ class Vidstream(val mainUrl: String) {
href,
page.url,
getQualityFromName(qual),
element.attr("href").contains(".m3u8")
type = INFER_TYPE
)
)
}

View File

@ -1,15 +1,46 @@
package com.lagradost.cloudstream3.extractors
import android.util.Base64
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
class Tubeless : Voe() {
override val name = "Tubeless"
override val mainUrl = "https://tubelessceliolymph.com"
}
class Simpulumlamerop : Voe() {
override val name = "Simplum"
override var mainUrl = "https://simpulumlamerop.com"
}
class Urochsunloath : Voe() {
override val name = "Uroch"
override var mainUrl = "https://urochsunloath.com"
}
class Yipsu : Voe() {
override val name = "Yipsu"
override var mainUrl = "https://yip.su"
}
class MetaGnathTuggers : Voe() {
override val name = "Metagnath"
override val mainUrl = "https://metagnathtuggers.com"
}
open class Voe : ExtractorApi() {
override val name = "Voe"
override val mainUrl = "https://voe.sx"
override val requiresReferer = true
private val linkRegex = "(http|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])".toRegex()
private val base64Regex = Regex("'.*'")
override suspend fun getUrl(
url: String,
@ -18,15 +49,36 @@ open class Voe : ExtractorApi() {
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url, referer = referer).document
val link = res.select("script").find { it.data().contains("const sources") }?.data()
?.substringAfter("\"hls\": \"")?.substringBefore("\",")
M3u8Helper.generateM3u8(
name,
link ?: return,
"$mainUrl/",
headers = mapOf("Origin" to "$mainUrl/")
).forEach(callback)
val script = res.select("script").find { it.data().contains("sources =") }?.data()
val link = Regex("[\"']hls[\"']:\\s*[\"'](.*)[\"']").find(script ?: return)?.groupValues?.get(1)
val videoLinks = mutableListOf<String>()
if (!link.isNullOrBlank()) {
videoLinks.add(
when {
linkRegex.matches(link) -> link
else -> String(Base64.decode(link, Base64.DEFAULT))
}
)
} else {
val link2 = base64Regex.find(script)?.value ?: return
val decoded = Base64.decode(link2, Base64.DEFAULT).toString()
val videoLinkDTO = AppUtils.parseJson<WcoSources>(decoded)
videoLinkDTO.let { videoLinks.add(it.toString()) }
}
videoLinks.forEach { videoLink ->
M3u8Helper.generateM3u8(
name,
videoLink,
"$mainUrl/",
headers = mapOf("Origin" to "$mainUrl/")
).forEach(callback)
}
}
}
data class WcoSources(
@JsonProperty("VideoLinkDTO") val VideoLinkDTO: String,
)
}

View File

@ -1,54 +0,0 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
open class VoeExtractor : ExtractorApi() {
override val name: String = "Voe"
override val mainUrl: String = "https://voe.sx"
override val requiresReferer = false
private data class ResponseLinks(
@JsonProperty("hls") val hls: String?,
@JsonProperty("mp4") val mp4: String?,
@JsonProperty("video_height") val label: Int?
//val type: String // Mp4
)
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val html = app.get(url).text
if (html.isNotBlank()) {
val src = html.substringAfter("const sources =").substringBefore(";")
// Remove last comma, it is not proper json otherwise
.replace("0,", "0")
// Make json use the proper quotes
.replace("'", "\"")
//Log.i(this.name, "Result => (src) ${src}")
parseJson<ResponseLinks?>(src)?.let { voeLink ->
//Log.i(this.name, "Result => (voeLink) ${voeLink}")
// Always defaults to the hls link, but returns the mp4 if null
val linkUrl = voeLink.hls ?: voeLink.mp4
val linkLabel = voeLink.label?.toString() ?: ""
if (!linkUrl.isNullOrEmpty()) {
return listOf(
ExtractorLink(
name = this.name,
source = this.name,
url = linkUrl,
quality = getQualityFromName(linkLabel),
referer = url,
isM3u8 = voeLink.hls != null
)
)
}
}
}
return emptyList()
}
}

View File

@ -0,0 +1,39 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.JsUnpacker
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getQualityFromName
import java.net.URI
open class Vtbe : ExtractorApi() {
override var name = "Vtbe"
override var mainUrl = "https://vtbe.to"
override val requiresReferer = true
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val response = app.get(url,referer=mainUrl).document
val extractedpack =response.selectFirst("script:containsData(function(p,a,c,k,e,d))")?.data().toString()
JsUnpacker(extractedpack).unpack()?.let { unPacked ->
Regex("sources:\\[\\{file:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link ->
return listOf(
ExtractorLink(
this.name,
this.name,
link,
referer ?: "",
Qualities.Unknown.value,
URI(link).path.endsWith(".m3u8")
)
)
}
}
return null
}
}

View File

@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.extractors.helper.NineAnimeHelper.encrypt
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
class Vidstreamz : WcoStream() {
@ -126,8 +127,7 @@ open class WcoStream : ExtractorApi() {
if (!response.text.startsWith("{")) throw ErrorLoadingException("Seems like 9Anime kiddies changed stuff again, Go touch some grass for bout an hour Or use a different Server")
return response.parsed<Response>().data.media.sources.map {
ExtractorLink(name, it.file,it.file,host,Qualities.Unknown.value,it.file.contains(".m3u8"))
ExtractorLink(name, it.file, it.file, host, Qualities.Unknown.value, type = INFER_TYPE)
}
}
}

View File

@ -0,0 +1,35 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
open class Wibufile : ExtractorApi() {
override val name: String = "Wibufile"
override val mainUrl: String = "https://wibufile.com"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url).text
val video = Regex("src: ['\"](.*?)['\"]").find(res)?.groupValues?.get(1)
callback.invoke(
ExtractorLink(
name,
name,
video ?: return,
"$mainUrl/",
Qualities.Unknown.value,
type = INFER_TYPE
)
)
}
}

View File

@ -8,6 +8,16 @@ import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
class StreamM4u : XStreamCdn() {
override val name: String = "StreamM4u"
override val mainUrl: String = "https://streamm4u.club"
}
class Fembed9hd : XStreamCdn() {
override var mainUrl = "https://fembed9hd.com"
override var name = "Fembed9hd"
}
class Cdnplayer: XStreamCdn() {
override val name: String = "Cdnplayer"
override val mainUrl: String = "https://cdnplayer.online"

View File

@ -70,19 +70,18 @@ open class YoutubeExtractor : ExtractorApi() {
}
}
ytVideos[url]?.mapNotNull {
if (it.isVideoOnly || it.height <= 0) return@mapNotNull null
if (it.isVideoOnly() || it.height <= 0) return@mapNotNull null
ExtractorLink(
this.name,
this.name,
it.url ?: return@mapNotNull null,
it.content ?: return@mapNotNull null,
"",
it.height
)
}?.forEach(callback)
ytVideosSubtitles[url]?.mapNotNull {
SubtitleFile(it.languageTag ?: return@mapNotNull null, it.url ?: return@mapNotNull null)
SubtitleFile(it.languageTag ?: return@mapNotNull null, it.content ?: return@mapNotNull null)
}?.forEach(subtitleCallback)
}
}

View File

@ -0,0 +1,100 @@
package com.lagradost.cloudstream3.extractors.helper
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.base64DecodeArray
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.utils.AppUtils
import java.security.DigestException
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
object AesHelper {
private const val HASH = "AES/CBC/PKCS5PADDING"
private const val KDF = "MD5"
fun cryptoAESHandler(
data: String,
pass: ByteArray,
encrypt: Boolean = true,
padding: String = HASH,
): String? {
val parse = AppUtils.tryParseJson<AesData>(data) ?: return null
val (key, iv) = generateKeyAndIv(
pass,
parse.s.hexToByteArray(),
ivLength = parse.iv.length / 2,
saltLength = parse.s.length / 2
) ?: return null
val cipher = Cipher.getInstance(padding)
return if (!encrypt) {
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
String(cipher.doFinal(base64DecodeArray(parse.ct)))
} else {
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
base64Encode(cipher.doFinal(parse.ct.toByteArray()))
}
}
// https://stackoverflow.com/a/41434590/8166854
fun generateKeyAndIv(
password: ByteArray,
salt: ByteArray,
hashAlgorithm: String = KDF,
keyLength: Int = 32,
ivLength: Int,
saltLength: Int,
iterations: Int = 1
): Pair<ByteArray,ByteArray>? {
val md = MessageDigest.getInstance(hashAlgorithm)
val digestLength = md.digestLength
val targetKeySize = keyLength + ivLength
val requiredLength = (targetKeySize + digestLength - 1) / digestLength * digestLength
val generatedData = ByteArray(requiredLength)
var generatedLength = 0
try {
md.reset()
while (generatedLength < targetKeySize) {
if (generatedLength > 0)
md.update(
generatedData,
generatedLength - digestLength,
digestLength
)
md.update(password)
md.update(salt, 0, saltLength)
md.digest(generatedData, generatedLength, digestLength)
for (i in 1 until iterations) {
md.update(generatedData, generatedLength, digestLength)
md.digest(generatedData, generatedLength, digestLength)
}
generatedLength += digestLength
}
return generatedData.copyOfRange(0, keyLength) to generatedData.copyOfRange(keyLength, targetKeySize)
} catch (e: DigestException) {
return null
}
}
fun String.hexToByteArray(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
private data class AesData(
@JsonProperty("ct") val ct: String,
@JsonProperty("iv") val iv: String,
@JsonProperty("s") val s: String
)
}

View File

@ -0,0 +1,158 @@
package com.lagradost.cloudstream3.extractors.helper
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.base64DecodeArray
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.nodes.Document
import java.net.URI
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
object GogoHelper {
/**
* @param id base64Decode(show_id) + IV
* @return the encryption key
* */
private fun getKey(id: String): String? {
return normalSafeApiCall {
id.map {
it.code.toString(16)
}.joinToString("").substring(0, 32)
}
}
// https://github.com/saikou-app/saikou/blob/45d0a99b8a72665a29a1eadfb38c506b842a29d7/app/src/main/java/ani/saikou/parsers/anime/extractors/GogoCDN.kt#L97
// No Licence on the function
private fun cryptoHandler(
string: String,
iv: String,
secretKeyString: String,
encrypt: Boolean = true
): String {
//println("IV: $iv, Key: $secretKeyString, encrypt: $encrypt, Message: $string")
val ivParameterSpec = IvParameterSpec(iv.toByteArray())
val secretKey = SecretKeySpec(secretKeyString.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
return if (!encrypt) {
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
String(cipher.doFinal(base64DecodeArray(string)))
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)
base64Encode(cipher.doFinal(string.toByteArray()))
}
}
/**
* @param iframeUrl something like https://gogoplay4.com/streaming.php?id=XXXXXX
* @param mainApiName used for ExtractorLink names and source
* @param iv secret iv from site, required non-null if isUsingAdaptiveKeys is off
* @param secretKey secret key for decryption from site, required non-null if isUsingAdaptiveKeys is off
* @param secretDecryptKey secret key to decrypt the response json, required non-null if isUsingAdaptiveKeys is off
* @param isUsingAdaptiveKeys generates keys from IV and ID, see getKey()
* @param isUsingAdaptiveData generate encrypt-ajax data based on $("script[data-name='episode']")[0].dataset.value
* */
suspend fun extractVidstream(
iframeUrl: String,
mainApiName: String,
callback: (ExtractorLink) -> Unit,
iv: String?,
secretKey: String?,
secretDecryptKey: String?,
// This could be removed, but i prefer it verbose
isUsingAdaptiveKeys: Boolean,
isUsingAdaptiveData: Boolean,
// If you don't want to re-fetch the document
iframeDocument: Document? = null
) = safeApiCall {
if ((iv == null || secretKey == null || secretDecryptKey == null) && !isUsingAdaptiveKeys)
return@safeApiCall
val id = Regex("id=([^&]+)").find(iframeUrl)!!.value.removePrefix("id=")
var document: Document? = iframeDocument
val foundIv =
iv ?: (document ?: app.get(iframeUrl).document.also { document = it })
.select("""div.wrapper[class*=container]""")
.attr("class").split("-").lastOrNull() ?: return@safeApiCall
val foundKey = secretKey ?: getKey(base64Decode(id) + foundIv) ?: return@safeApiCall
val foundDecryptKey = secretDecryptKey ?: foundKey
val uri = URI(iframeUrl)
val mainUrl = "https://" + uri.host
val encryptedId = cryptoHandler(id, foundIv, foundKey)
val encryptRequestData = if (isUsingAdaptiveData) {
// Only fetch the document if necessary
val realDocument = document ?: app.get(iframeUrl).document
val dataEncrypted =
realDocument.select("script[data-name='episode']").attr("data-value")
val headers = cryptoHandler(dataEncrypted, foundIv, foundKey, false)
"id=$encryptedId&alias=$id&" + headers.substringAfter("&")
} else {
"id=$encryptedId&alias=$id"
}
val jsonResponse =
app.get(
"$mainUrl/encrypt-ajax.php?$encryptRequestData",
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
)
val dataencrypted =
jsonResponse.text.substringAfter("{\"data\":\"").substringBefore("\"}")
val datadecrypted = cryptoHandler(dataencrypted, foundIv, foundDecryptKey, false)
val sources = AppUtils.parseJson<GogoSources>(datadecrypted)
suspend fun invokeGogoSource(
source: GogoSource,
sourceCallback: (ExtractorLink) -> Unit
) {
if (source.file.contains(".m3u8")) {
M3u8Helper.generateM3u8(
mainApiName,
source.file,
mainUrl,
headers = mapOf("Origin" to "https://plyr.link")
).forEach(sourceCallback)
} else {
sourceCallback.invoke(
ExtractorLink(
mainApiName,
mainApiName,
source.file,
mainUrl,
getQualityFromName(source.label),
)
)
}
}
sources.source?.forEach {
invokeGogoSource(it, callback)
}
sources.sourceBk?.forEach {
invokeGogoSource(it, callback)
}
}
data class GogoSources(
@JsonProperty("source") val source: List<GogoSource>?,
@JsonProperty("sourceBk") val sourceBk: List<GogoSource>?,
)
data class GogoSource(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String?,
@JsonProperty("type") val type: String?,
@JsonProperty("default") val default: String? = null
)
}

View File

@ -1,30 +0,0 @@
package com.lagradost.cloudstream3.metaproviders
import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi
import com.lagradost.cloudstream3.utils.SyncUtil
object SyncRedirector {
val syncApis = SyncApis
suspend fun redirect(url: String, preferredUrl: String): String {
for (api in syncApis) {
if (url.contains(api.mainUrl)) {
val otherApi = when (api.name) {
aniListApi.name -> "anilist"
malApi.name -> "myanimelist"
else -> return url
}
return SyncUtil.getUrlsFromId(api.getIdFromUrl(url), otherApi).firstOrNull { realUrl ->
realUrl.contains(preferredUrl)
} ?: run {
throw ErrorLoadingException("Page does not exist on $preferredUrl")
}
}
}
return url
}
}

View File

@ -21,10 +21,11 @@ class CrossTmdbProvider : TmdbProvider() {
return Regex("""[^a-zA-Z0-9-]""").replace(name, "")
}
private val validApis by lazy {
apis.filter { it.lang == this.lang && it::class.java != this::class.java }
//.distinctBy { it.uniqueId }
}
private val validApis
get() =
synchronized(apis) { apis.filter { it.lang == this.lang && it::class.java != this::class.java } }
//.distinctBy { it.uniqueId }
data class CrossMetaData(
@JsonProperty("isSuccess") val isSuccess: Boolean,
@ -60,7 +61,8 @@ class CrossTmdbProvider : TmdbProvider() {
override suspend fun load(url: String): LoadResponse? {
val base = super.load(url)?.apply {
this.recommendations = this.recommendations?.filterIsInstance<MovieSearchResponse>() // TODO REMOVE
this.recommendations =
this.recommendations?.filterIsInstance<MovieSearchResponse>() // TODO REMOVE
val matchName = filterName(this.name)
when (this) {
is MovieLoadResponse -> {
@ -98,6 +100,7 @@ class CrossTmdbProvider : TmdbProvider() {
this.dataUrl =
CrossMetaData(true, data.map { it.apiName to it.dataUrl }).toJson()
}
else -> {
throw ErrorLoadingException("Nothing besides movies are implemented for this provider")
}

View File

@ -1,70 +0,0 @@
package com.lagradost.cloudstream3.metaproviders
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi
import com.lagradost.cloudstream3.syncproviders.providers.MALApi
import com.lagradost.cloudstream3.utils.SyncUtil
// wont be implemented
class MultiAnimeProvider : MainAPI() {
override var name = "MultiAnime"
override var lang = "en"
override val usesWebView = true
override val supportedTypes = setOf(TvType.Anime)
private val syncApi: SyncAPI = aniListApi
private val syncUtilType by lazy {
when (syncApi) {
is AniListApi -> "anilist"
is MALApi -> "myanimelist"
else -> throw ErrorLoadingException("Invalid Api")
}
}
private val validApis by lazy {
APIHolder.apis.filter {
it.lang == this.lang && it::class.java != this::class.java && it.supportedTypes.contains(
TvType.Anime
)
}
}
private fun filterName(name: String): String {
return Regex("""[^a-zA-Z0-9-]""").replace(name, "")
}
override suspend fun search(query: String): List<SearchResponse>? {
return syncApi.search(query)?.map {
AnimeSearchResponse(it.name, it.url, this.name, TvType.Anime, it.posterUrl)
}
}
override suspend fun load(url: String): LoadResponse? {
return syncApi.getResult(url)?.let { res ->
val data = SyncUtil.getUrlsFromId(res.id, syncUtilType).amap { url ->
validApis.firstOrNull { api -> url.startsWith(api.mainUrl) }?.load(url)
}.filterNotNull()
val type =
if (data.any { it.type == TvType.AnimeMovie }) TvType.AnimeMovie else TvType.Anime
newAnimeLoadResponse(
res.title ?: throw ErrorLoadingException("No Title found"),
url,
type
) {
posterUrl = res.posterUrl
plot = res.synopsis
tags = res.genres
rating = res.publicScore
addTrailer(res.trailers)
addAniListId(res.id.toIntOrNull())
recommendations = res.recommendations
}
}
}
}

View File

@ -0,0 +1,56 @@
package com.lagradost.cloudstream3.metaproviders
import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.SyncIdName
object SyncRedirector {
val syncApis = SyncApis
private val syncIds =
listOf(
SyncIdName.MyAnimeList to Regex("""myanimelist\.net\/anime\/(\d+)"""),
SyncIdName.Anilist to Regex("""anilist\.co\/anime\/(\d+)""")
)
suspend fun redirect(
url: String,
providerApi: MainAPI
): String {
// Deprecated since providers should do this instead!
// Tries built in ID -> ProviderUrl
/*
for (api in syncApis) {
if (url.contains(api.mainUrl)) {
val otherApi = when (api.name) {
aniListApi.name -> "anilist"
malApi.name -> "myanimelist"
else -> return url
}
SyncUtil.getUrlsFromId(api.getIdFromUrl(url), otherApi).firstOrNull { realUrl ->
realUrl.contains(providerApi.mainUrl)
}?.let {
return it
}
// ?: run {
// throw ErrorLoadingException("Page does not exist on $preferredUrl")
// }
}
}
*/
// Tries provider solution
// This goes through all sync ids and finds supported id by said provider
return syncIds.firstNotNullOfOrNull { (syncName, syncRegex) ->
if (providerApi.supportedSyncNames.contains(syncName)) {
syncRegex.find(url)?.value?.let {
suspendSafeApiCall {
providerApi.getLoadUrl(syncName, it)
}
}
} else null
} ?: url
}
}

View File

@ -105,6 +105,7 @@ open class TmdbProvider : MainAPI() {
this.id,
episode.episode_number,
episode.season_number,
this.name ?: this.original_name,
).toJson(),
episode.name,
episode.season_number,
@ -122,6 +123,7 @@ open class TmdbProvider : MainAPI() {
this.id,
episodeNum,
season.season_number,
this.name ?: this.original_name,
).toJson(),
season = season.season_number
)
@ -151,6 +153,8 @@ open class TmdbProvider : MainAPI() {
recommendations = (this@toLoadResponse.recommendations
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
addActors(credits?.cast?.toList().toActors())
contentRating = fetchContentRating(id, "US")
}
}
@ -193,6 +197,8 @@ open class TmdbProvider : MainAPI() {
recommendations = (this@toLoadResponse.recommendations
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
addActors(credits?.cast?.toList().toActors())
contentRating = fetchContentRating(id, "US")
}
}
@ -264,6 +270,26 @@ open class TmdbProvider : MainAPI() {
return null
}
open suspend fun fetchContentRating(id: Int?, country: String): String? {
id ?: return null
val contentRatings = tmdb.tvService().content_ratings(id).awaitResponse().body()?.results
return if (!contentRatings.isNullOrEmpty()) {
contentRatings.firstOrNull { it: ContentRating ->
it.iso_3166_1 == country
}?.rating
} else {
val releaseDates = tmdb.moviesService().releaseDates(id).awaitResponse().body()?.results
val certification = releaseDates?.firstOrNull { it: ReleaseDatesResult ->
it.iso_3166_1 == country
}?.release_dates?.firstOrNull { it: ReleaseDate ->
!it.certification.isNullOrBlank()
}?.certification
certification
}
}
// Possible to add recommendations and such here.
override suspend fun load(url: String): LoadResponse? {
// https://www.themoviedb.org/movie/7445-brothers

View File

@ -0,0 +1,440 @@
package com.lagradost.cloudstream3.metaproviders
import android.net.Uri
import com.lagradost.cloudstream3.*
import com.fasterxml.jackson.annotation.JsonAlias
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import java.util.Locale
import java.text.SimpleDateFormat
import kotlin.math.roundToInt
open class TraktProvider : MainAPI() {
override var name = "Trakt"
override val hasMainPage = true
override val providerType = ProviderType.MetaProvider
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
)
private val traktClientId = base64Decode("N2YzODYwYWQzNGI4ZTZmOTdmN2I5MTA0ZWQzMzEwOGI0MmQ3MTdlMTM0MmM2NGMxMTg5NGE1MjUyYTQ3NjE3Zg==")
private val traktApiUrl = base64Decode("aHR0cHM6Ly9hcGl6LnRyYWt0LnR2")
override val mainPage = mainPageOf(
"$traktApiUrl/movies/trending" to "Trending Movies", //Most watched movies right now
"$traktApiUrl/movies/popular" to "Popular Movies", //The most popular movies for all time
"$traktApiUrl/shows/trending" to "Trending Shows", //Most watched Shows right now
"$traktApiUrl/shows/popular" to "Popular Shows", //The most popular Shows for all time
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val apiResponse = getApi("${request.data}?extended=cloud9,full&page=$page")
val results = parseJson<List<MediaDetails>>(apiResponse).map { element ->
element.toSearchResponse()
}
return newHomePageResponse(request.name, results)
}
private fun MediaDetails.toSearchResponse(): SearchResponse {
val media = this.media ?: this
val mediaType = if (media.ids?.tvdb == null) TvType.Movie else TvType.TvSeries
val poster = media.images?.poster?.firstOrNull()
if (mediaType == TvType.Movie) {
return newMovieSearchResponse(
name = media.title!!,
url = Data(
type = mediaType,
mediaDetails = media,
).toJson(),
type = TvType.Movie,
) {
posterUrl = fixPath(poster)
}
} else {
return newTvSeriesSearchResponse(
name = media.title!!,
url = Data(
type = mediaType,
mediaDetails = media,
).toJson(),
type = TvType.TvSeries,
) {
this.posterUrl = fixPath(poster)
}
}
}
override suspend fun search(query: String): List<SearchResponse>? {
val apiResponse = getApi("$traktApiUrl/search/movie,show?extended=cloud9,full&limit=20&page=1&query=$query")
val results = parseJson<List<MediaDetails>>(apiResponse).map { element ->
element.toSearchResponse()
}
return results
}
override suspend fun load(url: String): LoadResponse {
val data = parseJson<Data>(url)
val mediaDetails = data.mediaDetails
val moviesOrShows = if (data.type == TvType.Movie) "movies" else "shows"
val posterUrl = mediaDetails?.images?.poster?.firstOrNull()
val backDropUrl = mediaDetails?.images?.fanart?.firstOrNull()
val resActor = getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/people?extended=cloud9,full")
val actors = parseJson<People>(resActor).cast?.map {
ActorData(
Actor(
name = it.person?.name!!,
image = getWidthImageUrl(it.person.images?.headshot?.firstOrNull(), "w500")
),
roleString = it.character
)
}
val resRelated = getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/related?extended=cloud9,full&limit=20")
val relatedMedia = parseJson<List<MediaDetails>>(resRelated).map { it.toSearchResponse() }
val isCartoon = mediaDetails?.genres?.contains("animation") == true || mediaDetails?.genres?.contains("anime") == true
val isAnime = isCartoon && (mediaDetails?.language == "zh" || mediaDetails?.language == "ja")
val isAsian = !isAnime && (mediaDetails?.language == "zh" || mediaDetails?.language == "ko")
val isBollywood = mediaDetails?.country == "in"
if (data.type == TvType.Movie) {
val linkData = LinkData(
id = mediaDetails?.ids?.tmdb,
traktId = mediaDetails?.ids?.trakt,
traktSlug = mediaDetails?.ids?.slug,
tmdbId = mediaDetails?.ids?.tmdb,
imdbId = mediaDetails?.ids?.imdb.toString(),
tvdbId = mediaDetails?.ids?.tvdb,
tvrageId = mediaDetails?.ids?.tvrage,
type = data.type.toString(),
title = mediaDetails?.title,
year = mediaDetails?.year,
orgTitle = mediaDetails?.title,
isAnime = isAnime,
//jpTitle = later if needed as it requires another network request,
airedDate = mediaDetails?.released
?: mediaDetails?.firstAired,
isAsian = isAsian,
isBollywood = isBollywood,
).toJson()
return newMovieLoadResponse(
name = mediaDetails?.title!!,
url = data.toJson(),
dataUrl = linkData.toJson(),
type = if (isAnime) TvType.AnimeMovie else TvType.Movie,
) {
this.name = mediaDetails.title
this.type = if (isAnime) TvType.AnimeMovie else TvType.Movie
this.posterUrl = getOriginalWidthImageUrl(posterUrl)
this.year = mediaDetails.year
this.plot = mediaDetails.overview
this.rating = mediaDetails.rating?.times(1000)?.roundToInt()
this.tags = mediaDetails.genres
this.duration = mediaDetails.runtime
this.recommendations = relatedMedia
this.actors = actors
this.comingSoon = isUpcoming(mediaDetails.released)
//posterHeaders
this.backgroundPosterUrl = getOriginalWidthImageUrl(backDropUrl)
this.contentRating = mediaDetails.certification
addTrailer(mediaDetails.trailer)
addImdbId(mediaDetails.ids?.imdb)
addTMDbId(mediaDetails.ids?.tmdb.toString())
}
} else {
val resSeasons = getApi("$traktApiUrl/shows/${mediaDetails?.ids?.trakt.toString()}/seasons?extended=cloud9,full,episodes")
val episodes = mutableListOf<Episode>()
val seasons = parseJson<List<Seasons>>(resSeasons)
val seasonsNames = mutableListOf<SeasonData>()
seasons.forEach { season ->
seasonsNames.add(
SeasonData(
season.number!!,
season.title
)
)
season.episodes?.map { episode ->
val linkData = LinkData(
id = mediaDetails?.ids?.tmdb,
traktId = mediaDetails?.ids?.trakt,
traktSlug = mediaDetails?.ids?.slug,
tmdbId = mediaDetails?.ids?.tmdb,
imdbId = mediaDetails?.ids?.imdb.toString(),
tvdbId = mediaDetails?.ids?.tvdb,
tvrageId = mediaDetails?.ids?.tvrage,
type = data.type.toString(),
season = episode.season,
episode = episode.number,
title = mediaDetails?.title,
year = mediaDetails?.year,
orgTitle = mediaDetails?.title,
isAnime = isAnime,
airedYear = mediaDetails?.year,
lastSeason = seasons.size,
epsTitle = episode.title,
//jpTitle = later if needed as it requires another network request,
date = episode.firstAired,
airedDate = episode.firstAired,
isAsian = isAsian,
isBollywood = isBollywood,
isCartoon = isCartoon
).toJson()
episodes.add(
Episode(
data = linkData.toJson(),
name = episode.title,
season = episode.season,
episode = episode.number,
posterUrl = fixPath(episode.images?.screenshot?.firstOrNull()),
rating = episode.rating?.times(10)?.roundToInt(),
description = episode.overview,
).apply {
this.addDate(episode.firstAired)
}
)
}
}
return newTvSeriesLoadResponse(
name = mediaDetails?.title!!,
url = data.toJson(),
type = if (isAnime) TvType.Anime else TvType.TvSeries,
episodes = episodes
) {
this.name = mediaDetails.title
this.type = if (isAnime) TvType.Anime else TvType.TvSeries
this.episodes = episodes
this.posterUrl = getOriginalWidthImageUrl(posterUrl)
this.year = mediaDetails.year
this.plot = mediaDetails.overview
this.showStatus = getStatus(mediaDetails.status)
this.rating = mediaDetails.rating?.times(1000)?.roundToInt()
this.tags = mediaDetails.genres
this.duration = mediaDetails.runtime
this.recommendations = relatedMedia
this.actors = actors
this.comingSoon = isUpcoming(mediaDetails.released)
//posterHeaders
this.seasonNames = seasonsNames
this.backgroundPosterUrl = getOriginalWidthImageUrl(backDropUrl)
this.contentRating = mediaDetails.certification
addTrailer(mediaDetails.trailer)
addImdbId(mediaDetails.ids?.imdb)
addTMDbId(mediaDetails.ids?.tmdb.toString())
}
}
}
private suspend fun getApi(url: String) : String {
return app.get(
url = url,
headers = mapOf(
"Content-Type" to "application/json",
"trakt-api-version" to "2",
"trakt-api-key" to traktClientId,
)
).toString()
}
private fun isUpcoming(dateString: String?): Boolean {
return try {
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val dateTime = dateString?.let { format.parse(it)?.time } ?: return false
APIHolder.unixTimeMS < dateTime
} catch (t: Throwable) {
logError(t)
false
}
}
private fun getStatus(t: String?): ShowStatus {
return when (t) {
"returning series" -> ShowStatus.Ongoing
"continuing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
private fun fixPath(url: String?): String? {
url ?: return null
return "https://$url"
}
private fun getWidthImageUrl(path: String?, width: String) : String? {
if (path == null) return null
if (!path.contains("image.tmdb.org")) return fixPath(path)
val fileName = Uri.parse(path).lastPathSegment ?: return null
return "https://image.tmdb.org/t/p/${width}/${fileName}"
}
private fun getOriginalWidthImageUrl(path: String?) : String? {
if (path == null) return null
if (!path.contains("image.tmdb.org")) return fixPath(path)
return getWidthImageUrl(path, "original")
}
data class Data(
val type: TvType? = null,
val mediaDetails: MediaDetails? = null,
)
data class MediaDetails(
@JsonProperty("title") val title: String? = null,
@JsonProperty("year") val year: Int? = null,
@JsonProperty("ids") val ids: Ids? = null,
@JsonProperty("tagline") val tagline: String? = null,
@JsonProperty("overview") val overview: String? = null,
@JsonProperty("released") val released: String? = null,
@JsonProperty("runtime") val runtime: Int? = null,
@JsonProperty("country") val country: String? = null,
@JsonProperty("updatedAt") val updatedAt: String? = null,
@JsonProperty("trailer") val trailer: String? = null,
@JsonProperty("homepage") val homepage: String? = null,
@JsonProperty("status") val status: String? = null,
@JsonProperty("rating") val rating: Double? = null,
@JsonProperty("votes") val votes: Long? = null,
@JsonProperty("comment_count") val commentCount: Long? = null,
@JsonProperty("language") val language: String? = null,
@JsonProperty("languages") val languages: List<String>? = null,
@JsonProperty("available_translations") val availableTranslations: List<String>? = null,
@JsonProperty("genres") val genres: List<String>? = null,
@JsonProperty("certification") val certification: String? = null,
@JsonProperty("aired_episodes") val airedEpisodes: Int? = null,
@JsonProperty("first_aired") val firstAired: String? = null,
@JsonProperty("airs") val airs: Airs? = null,
@JsonProperty("network") val network: String? = null,
@JsonProperty("images") val images: Images? = null,
@JsonProperty("movie") @JsonAlias("show") val media: MediaDetails? = null
)
data class Airs(
@JsonProperty("day") val day: String? = null,
@JsonProperty("time") val time: String? = null,
@JsonProperty("timezone") val timezone: String? = null,
)
data class Ids(
@JsonProperty("trakt") val trakt: Int? = null,
@JsonProperty("slug") val slug: String? = null,
@JsonProperty("tvdb") val tvdb: Int? = null,
@JsonProperty("imdb") val imdb: String? = null,
@JsonProperty("tmdb") val tmdb: Int? = null,
@JsonProperty("tvrage") val tvrage: String? = null,
)
data class Images(
@JsonProperty("fanart") val fanart: List<String>? = null,
@JsonProperty("poster") val poster: List<String>? = null,
@JsonProperty("logo") val logo: List<String>? = null,
@JsonProperty("clearart") val clearart: List<String>? = null,
@JsonProperty("banner") val banner: List<String>? = null,
@JsonProperty("thumb") val thumb: List<String>? = null,
@JsonProperty("screenshot") val screenshot: List<String>? = null,
@JsonProperty("headshot") val headshot: List<String>? = null,
)
data class People(
@JsonProperty("cast") val cast: List<Cast>? = null,
)
data class Cast(
@JsonProperty("character") val character: String? = null,
@JsonProperty("characters") val characters: List<String>? = null,
@JsonProperty("episode_count") val episodeCount: Long? = null,
@JsonProperty("person") val person: Person? = null,
@JsonProperty("images") val images: Images? = null,
)
data class Person(
@JsonProperty("name") val name: String? = null,
@JsonProperty("ids") val ids: Ids? = null,
@JsonProperty("images") val images: Images? = null,
)
data class Seasons(
@JsonProperty("aired_episodes") val airedEpisodes: Int? = null,
@JsonProperty("episode_count") val episodeCount: Int? = null,
@JsonProperty("episodes") val episodes: List<TraktEpisode>? = null,
@JsonProperty("first_aired") val firstAired: String? = null,
@JsonProperty("ids") val ids: Ids? = null,
@JsonProperty("images") val images: Images? = null,
@JsonProperty("network") val network: String? = null,
@JsonProperty("number") val number: Int? = null,
@JsonProperty("overview") val overview: String? = null,
@JsonProperty("rating") val rating: Double? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("updated_at") val updatedAt: String? = null,
@JsonProperty("votes") val votes: Int? = null,
)
data class TraktEpisode(
@JsonProperty("available_translations") val availableTranslations: List<String>? = null,
@JsonProperty("comment_count") val commentCount: Int? = null,
@JsonProperty("episode_type") val episodeType: String? = null,
@JsonProperty("first_aired") val firstAired: String? = null,
@JsonProperty("ids") val ids: Ids? = null,
@JsonProperty("images") val images: Images? = null,
@JsonProperty("number") val number: Int? = null,
@JsonProperty("number_abs") val numberAbs: Int? = null,
@JsonProperty("overview") val overview: String? = null,
@JsonProperty("rating") val rating: Double? = null,
@JsonProperty("runtime") val runtime: Int? = null,
@JsonProperty("season") val season: Int? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("updated_at") val updatedAt: String? = null,
@JsonProperty("votes") val votes: Int? = null,
)
data class LinkData(
val id: Int? = null,
val traktId: Int? = null,
val traktSlug: String? = null,
val tmdbId: Int? = null,
val imdbId: String? = null,
val tvdbId: Int? = null,
val tvrageId: String? = null,
val type: String? = null,
val season: Int? = null,
val episode: Int? = null,
val aniId: String? = null,
val animeId: String? = null,
val title: String? = null,
val year: Int? = null,
val orgTitle: String? = null,
val isAnime: Boolean = false,
val airedYear: Int? = null,
val lastSeason: Int? = null,
val epsTitle: String? = null,
val jpTitle: String? = null,
val date: String? = null,
val airedDate: String? = null,
val isAsian: Boolean = false,
val isBollywood: Boolean = false,
val isCartoon: Boolean = false,
)
}

View File

@ -0,0 +1,16 @@
package com.lagradost.cloudstream3.mvvm
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
/** NOTE: Only one observer at a time per value */
fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
liveData.removeObservers(this)
liveData.observe(this) { it?.let { t -> action(t) } }
}
/** NOTE: Only one observer at a time per value */
fun <T> LifecycleOwner.observeNullable(liveData: LiveData<T>, action: (t: T) -> Unit) {
liveData.removeObservers(this)
liveData.observe(this) { action(it) }
}

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