1
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-09-19 23:40:51 +02:00

Compare commits

...

163 Commits

Author SHA1 Message Date
Christian Schabesberger
48f966e7db add changelog for 730 2019-03-14 09:24:02 +01:00
Christian Schabesberger
d8746dc592 hotfix decrypt function and move on to version v0.16.1 2019-03-14 09:20:37 +01:00
Christian Schabesberger
f24fab0fa2 fix brake when selecting a mediaccc channel form subscription page 2019-02-25 12:24:48 +01:00
Christian Schabesberger
261620fd13 Merge branch 'master' into release_v0.16.0 2019-02-24 23:06:06 +01:00
Christian Schabesberger
9af6effad9 move on to version 0.16.0 2019-02-24 22:52:07 +01:00
Christian Schabesberger
92602916dd merge weblate 2019-02-24 22:51:08 +01:00
Nathan Follens
6c7b90e1c3 Translated using Weblate (Flemish)
Currently translated at 100.0% (443 of 443 strings)
2019-02-24 06:18:27 +01:00
Nathan Follens
d8e57144f7 Translated using Weblate (Dutch)
Currently translated at 100.0% (443 of 443 strings)
2019-02-24 06:18:27 +01:00
Christian Schabesberger
e69c45a246 Merge pull request #1650 from yausername/dev
comments support
2019-02-21 15:50:21 +01:00
Ritvik Saraf
3f87a6d714 Merge remote-tracking branch 'origin/dev' into dev 2019-02-20 05:29:34 +05:30
Ritvik Saraf
841124b1f3 updated extractor, fixed settings padding 2019-02-20 05:24:33 +05:30
Hosted Weblate
257a878ef4 Merge branch 'origin/dev' into Weblate. 2019-02-19 19:18:29 +01:00
84436
07d3f82912 Translated using Weblate (Vietnamese)
Currently translated at 99.3% (440 of 443 strings)
2019-02-19 19:18:26 +01:00
Ali Demirtas
7d3eb4f5a6 Translated using Weblate (Turkish)
Currently translated at 100.0% (443 of 443 strings)
2019-02-19 19:18:12 +01:00
srkrishna
0efcc55373 Translated using Weblate (Tamil)
Currently translated at 34.5% (153 of 443 strings)
2019-02-19 19:18:12 +01:00
Christian Schabesberger
eafceb8a6c Merge branch 'dev' into dev 2019-02-19 17:35:49 +01:00
Christian Schabesberger
5ac8318e71 Merge pull request #2136 from TeamNewPipe/db_doc
add database doc in dia
2019-02-19 16:06:11 +01:00
Christian Schabesberger
7981f9dc91 add database doc in dia 2019-02-19 16:03:10 +01:00
Christian Schabesberger
a9bf04cbc6 Merge pull request #2135 from TeamNewPipe/firetv
add support for search in amazon firetv
2019-02-19 15:00:22 +01:00
Christian Schabesberger
4b5591d884 move firetv utils into utils package 2019-02-19 14:57:49 +01:00
Christian Schabesberger
c08197f025 Merge branch 'dev' into feature/amazonfiretv-search-support 2019-02-19 14:54:48 +01:00
Christian Schabesberger
5d22eabfa3 Merge pull request #2092 from connectety/updated-urls
support for youtube-nocookie.com
2019-02-19 14:30:56 +01:00
Christian Schabesberger
c3a38e384a Merge branch 'dev' into updated-urls 2019-02-19 14:30:34 +01:00
Christian Schabesberger
0d3dd94559 Merge pull request #2120 from Redirion/patch-1
Fix delayed ducking of Audio
2019-02-19 14:30:11 +01:00
Christian Schabesberger
9cdaa37519 Merge branch 'dev' into patch-1 2019-02-19 14:29:34 +01:00
Christian Schabesberger
202a319d69 Merge pull request #2129 from TeamNewPipe/remove-old-player
Remove old player from the manifest
2019-02-19 14:29:02 +01:00
Christian Schabesberger
198384b2ed Merge branch 'dev' into remove-old-player 2019-02-19 14:28:53 +01:00
Christian Schabesberger
9d8b070f1e Merge pull request #2133 from kapodamy/popup-player-fixup
Fix random Popup player crash
2019-02-19 14:28:04 +01:00
dimqua
28ba2d5008 Translated using Weblate (Russian)
Currently translated at 100.0% (443 of 443 strings)
2019-02-19 14:07:27 +01:00
Arthur
37ddd63d27 Translated using Weblate (Russian)
Currently translated at 100.0% (443 of 443 strings)
2019-02-19 14:07:26 +01:00
dimqua
d7f8b8c1e0 Translated using Weblate (Russian)
Currently translated at 97.5% (432 of 443 strings)
2019-02-18 13:28:20 +01:00
Arthur
9e70c5bbea Translated using Weblate (Russian)
Currently translated at 97.5% (432 of 443 strings)
2019-02-18 13:28:19 +01:00
kapodamy
4dd572063e fix crash while switching from popup to fullscreen player, or closing the popup player. 2019-02-17 16:59:35 -03:00
TobiGr
db9cf95648 Remove old player from the manifest
See https://github.com/TeamNewPipe/NewPipe/pull/1884 for more info
2019-02-17 09:52:05 +01:00
Ritvik Saraf
df6bae4712 merged upstream/dev 2019-02-16 02:06:18 +05:30
Ritvik Saraf
56cb8209b8 refactored comments capability 2019-02-16 01:23:26 +05:30
WaldiS
aba9c2e113 Translated using Weblate (Polish)
Currently translated at 100.0% (443 of 443 strings)
2019-02-15 17:24:20 +01:00
Ali Demirtas
3d25008739 Translated using Weblate (Turkish)
Currently translated at 97.5% (432 of 443 strings)
2019-02-14 10:11:03 +01:00
Redirion
9437f057d0 Fix delayed ducking of Audio
Scenario: listening to a video on NewPipe over Bluetooth and a Notification Sound causes audio focus event AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK.

Problem: With the current implementation animateAudio would cause the audio to reach the target volume AFTER the notification sound is played, which is irritating and annoying.

Solution: animateAudio should just be used on focusGain where it is sensible to increase audio gradually. On ducking event the reaction should be immediate.

This very simple fix does this. Please approve.
2019-02-14 09:52:46 +01:00
Emanuele Petriglia
917d6089a7 Translated using Weblate (Italian)
Currently translated at 97.5% (432 of 443 strings)
2019-02-13 19:10:46 +01:00
toanpv
f19e99e3ad Translated using Weblate (Vietnamese)
Currently translated at 74.9% (332 of 443 strings)
2019-02-13 12:11:48 +01:00
Allan Nordhøy
2d0fb05fa6 Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.8% (429 of 443 strings)
2019-02-13 12:11:46 +01:00
Chris
c617f2dfad Translated using Weblate (Malay)
Currently translated at 100.0% (443 of 443 strings)
2019-02-13 12:11:46 +01:00
naofum
747c5fc89a Translated using Weblate (Japanese)
Currently translated at 96.6% (428 of 443 strings)
2019-02-13 12:11:14 +01:00
Chris
4f662ef203 Translated using Weblate (Indonesian)
Currently translated at 100.0% (443 of 443 strings)
2019-02-13 12:11:13 +01:00
Le Poisson Libre
eb274ad88f Translated using Weblate (French)
Currently translated at 91.9% (407 of 443 strings)
2019-02-13 12:11:09 +01:00
Chris
bd7b41be9b Translated using Weblate (English)
Currently translated at 99.1% (439 of 443 strings)
2019-02-13 12:11:07 +01:00
Chris
076720bfff Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (443 of 443 strings)
2019-02-13 12:11:06 +01:00
Osoitz
2aadae407e Translated using Weblate (Basque)
Currently translated at 100.0% (443 of 443 strings)
2019-02-13 12:11:05 +01:00
Rex_sa
b16bb07774 Translated using Weblate (Arabic)
Currently translated at 100.0% (443 of 443 strings)
2019-02-13 12:11:00 +01:00
naofum
81dd083388 Translated using Weblate (Japanese)
Currently translated at 98.4% (436 of 443 strings)
2019-02-12 16:20:23 +01:00
Chris
92d4cef1e2 Translated using Weblate (Japanese)
Currently translated at 98.4% (436 of 443 strings)
2019-02-12 16:20:22 +01:00
C. Rüdinger
d2cd79dcf5 Translated using Weblate (German)
Currently translated at 99.8% (442 of 443 strings)
2019-02-10 23:34:08 +01:00
Hosted Weblate
0ef8b391e4 Merge branch 'origin/dev' into Weblate. 2019-02-09 13:57:02 +01:00
Eduardo Caron
0fbd105977 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:57:02 +01:00
ssantos
5c23af541e Translated using Weblate (Portuguese)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:57 +01:00
WaldiS
db021ff78b Translated using Weblate (Polish)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:57 +01:00
Allan Nordhøy
31294c6f54 Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.8% (429 of 443 strings)
2019-02-09 13:56:56 +01:00
JS Ahn
03d3495759 Translated using Weblate (Korean)
Currently translated at 78.6% (348 of 443 strings)
2019-02-09 13:56:56 +01:00
ssantos
4644e105a8 Translated using Weblate (German)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:53 +01:00
Tobias Groza
af5002508d Translated using Weblate (German)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:52 +01:00
Nathan Follens
9416d2b9c7 Translated using Weblate (Flemish)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:52 +01:00
Nathan Follens
f60f5d5a6c Translated using Weblate (Dutch)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:46 +01:00
ezjerry liao
26d00f87a8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 13:56:44 +01:00
Nathan Follens
6c33ea423c Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.6% (428 of 443 strings)
2019-02-09 13:56:40 +01:00
Connectety-W
ad354aca4e added support for youtube-nocookie.com 2019-02-09 12:30:14 +01:00
Christian Schabesberger
ce6a5ebf0a Merge pull request #2107 from chin123/fix_padding_settings
Fix padding in settings layout (Fixes #1866)
2019-02-09 09:08:20 +01:00
Yaron Shahrabani
d66ef38e8d Translated using Weblate (Hebrew)
Currently translated at 100.0% (443 of 443 strings)
2019-02-09 03:38:29 +01:00
Chinmaya Krishnan Mahesh
1b6c49f621 Fix padding in settings layout (Fixes #1866) 2019-02-08 17:33:35 -06:00
Allan Nordhøy
0262c83815 Translated using Weblate (English)
Currently translated at 98.9% (438 of 443 strings)
2019-02-08 21:38:01 +01:00
Allan Nordhøy
c212934130 Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.8% (429 of 443 strings)
2019-02-07 15:12:26 +01:00
Yaron Shahrabani
ac30e47e59 Translated using Weblate (Hebrew)
Currently translated at 98.2% (435 of 443 strings)
2019-02-06 20:36:39 +01:00
Yehuda Levy
d640057453 Translated using Weblate (Hebrew)
Currently translated at 90.1% (399 of 443 strings)
2019-02-06 09:17:45 +01:00
Yaron Shahrabani
0cea136d4d Translated using Weblate (Hebrew)
Currently translated at 90.1% (399 of 443 strings)
2019-02-06 09:17:44 +01:00
Hosted Weblate
9b3d93e734 Merge branch 'origin/dev' into Weblate. 2019-02-06 08:40:24 +01:00
Emin Tufan Çetin
ca3782ac62 Translated using Weblate (Turkish)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:40:24 +01:00
dimqua
dc9ffb7fd5 Translated using Weblate (Russian)
Currently translated at 96.8% (427 of 441 strings)
2019-02-06 08:40:23 +01:00
WaldiS
b21b3a55fe Translated using Weblate (Polish)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:40:21 +01:00
Mostafa Ahangarha
e62bd85a7a Translated using Weblate (Persian)
Currently translated at 57.8% (255 of 441 strings)
2019-02-06 08:40:19 +01:00
Michael Moroni
fed221b008 Translated using Weblate (Italian)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:40:18 +01:00
Terry Louwers
935298d159 Translated using Weblate (Dutch)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:40:17 +01:00
Nathan Follens
909919250c Translated using Weblate (Dutch)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:40:14 +01:00
Emil Tang Kristensen
d24f278f7c Translated using Weblate (Danish)
Currently translated at 85.7% (378 of 441 strings)
2019-02-06 08:40:14 +01:00
赖文胜
ca408a495c Translated using Weblate (Chinese (Simplified))
Currently translated at 97.1% (428 of 441 strings)
2019-02-06 08:39:42 +01:00
Sérgio Marques
ee99719137 Translated using Weblate (Portuguese)
Currently translated at 100.0% (441 of 441 strings)
2019-02-06 08:39:36 +01:00
Christian Schabesberger
5fb0729eae Merge pull request #2083 from TeamNewPipe/ccc
Add MediaCCC support
2019-02-05 18:28:22 +01:00
Christian Schabesberger
a1db3187cd Merge branch 'dev' into ccc 2019-02-05 18:28:17 +01:00
Christian Schabesberger
488a3cf1ff Merge pull request #2084 from TeamNewPipe/splash
add splash screen
2019-02-05 18:27:15 +01:00
Christian Schabesberger
1253a620a4 Merge pull request #2094 from def14nt/add-instable-warning
Added a warning about instability
2019-02-05 18:27:02 +01:00
Christian Schabesberger
64547fc4a7 remove splash for older android 2019-02-05 18:24:34 +01:00
Emil Tang Kristensen
d643d140cf Added translation using Weblate (Danish) 2019-02-04 20:57:57 +01:00
Ali Demirtas
222e2e3242 Translated using Weblate (Turkish)
Currently translated at 100.0% (441 of 441 strings)
2019-02-04 12:37:19 +01:00
Ali Demirtas
ea7b6daf26 Translated using Weblate (Turkish)
Currently translated at 100.0% (441 of 441 strings)
2019-02-04 02:10:01 +01:00
DefiantDog66
14cfab495d Added a warning about instability
This is a follow up to TeamNewPipe#2069. I've removed the "WARNING" from the second one as it looks a bit silly to have the same thing twice, when the user is already attracted to the first one, which means they will most probably read the second warning.

I can revert this if you don't like it.
2019-02-03 19:47:51 +00:00
Alec Holmes
ed4b4a1a3c Updated search fragment to be amazon fire tv friendly 2019-02-01 13:02:28 +00:00
Hosted Weblate
511c552188 Merge branch 'origin/dev' into Weblate. 2019-02-01 09:37:22 +01:00
ssantos
8c650219eb Translated using Weblate (Portuguese)
Currently translated at 100.0% (441 of 441 strings)
2019-02-01 09:37:22 +01:00
WaldiS
189b779abe Translated using Weblate (Polish)
Currently translated at 100.0% (441 of 441 strings)
2019-02-01 09:37:18 +01:00
Michael Moroni
c26074b184 Translated using Weblate (Italian)
Currently translated at 100.0% (441 of 441 strings)
2019-02-01 09:37:16 +01:00
Emanuele Petriglia
6c70779ff1 Translated using Weblate (Italian)
Currently translated at 100.0% (441 of 441 strings)
2019-02-01 09:37:15 +01:00
Yaron Shahrabani
73897481ac Translated using Weblate (Hebrew)
Currently translated at 83.7% (369 of 441 strings)
2019-02-01 09:37:11 +01:00
C. Rüdinger
a62c523ed5 Translated using Weblate (German)
Currently translated at 100.0% (441 of 441 strings)
2019-02-01 09:37:08 +01:00
Florian
0f46f57b52 Translated using Weblate (French)
Currently translated at 89.8% (396 of 441 strings)
2019-02-01 09:37:08 +01:00
Nathan Follens
bc4d65a20c Translated using Weblate (Dutch)
Currently translated at 86.4% (381 of 441 strings)
2019-02-01 09:37:07 +01:00
Vojtěch Šamla
f1e9a44ad9 Translated using Weblate (Czech)
Currently translated at 88.4% (390 of 441 strings)
2019-02-01 09:37:06 +01:00
Marc Riera
61972c4719 Translated using Weblate (Catalan)
Currently translated at 92.1% (406 of 441 strings)
2019-02-01 09:37:05 +01:00
Almin Agic
9183c9c220 Translated using Weblate (Bosnian (latin))
Currently translated at 4.3% (19 of 441 strings)
2019-02-01 09:37:03 +01:00
Rex_sa
1ce59f13ff Translated using Weblate (Arabic)
Currently translated at 87.8% (387 of 441 strings)
2019-02-01 09:37:00 +01:00
Christian Schabesberger
1bac5db6d5 add splash 2019-01-31 18:13:00 +01:00
Christian Schabesberger
58f2c4d8e6 Merge branch 'dev' into ccc 2019-01-31 16:48:22 +01:00
Robin
2c2c61b2fc Add Artist and Duration to MediaDescription 2019-01-31 16:47:33 +01:00
Christian Schabesberger
98b04a4a83 Merge branch 'dev' into ccc 2019-01-31 14:28:10 +01:00
Christian Schabesberger
3ac64c44f4 Merge pull request #1900 from anoymouserver/patch-1
support for invidio.us links
2019-01-31 14:10:10 +01:00
Christian Schabesberger
3375847302 Merge branch 'dev' into patch-1 2019-01-31 14:02:24 +01:00
Christian Schabesberger
14043c86f5 fix backstack issue with mediaccc 2019-01-31 13:24:02 +01:00
Jeff Huang
030117780a Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (441 of 441 strings)
2019-01-31 08:57:07 +01:00
Benedikt Freisen
971c9fe5a1 Translated using Weblate (German)
Currently translated at 100.0% (441 of 441 strings)
2019-01-30 08:49:53 +01:00
Ritvik Saraf
77c6d3d576 merged upstream/dev 2019-01-29 22:32:58 +05:30
Christian Schabesberger
6edbfe2a6f add content filter to mediaccc 2019-01-29 17:20:30 +01:00
Christian Schabesberger
d0a3125df4 fox ogg 2019-01-29 16:13:46 +01:00
Christian Schabesberger
d8c76d4c21 add conferences 2019-01-29 15:39:18 +01:00
Christian Schabesberger
a1cc0897df make frontend not crash on scrolling on ccc search 2019-01-29 15:39:18 +01:00
Christian Schabesberger
e88a90f242 add theming to mediaccc 2019-01-29 15:39:18 +01:00
Christian Schabesberger
1ae54f6f8c further compatiblity fix for meadic.ccc 2019-01-29 15:39:18 +01:00
Hosted Weblate
8a4cb484fa Merge branch 'origin/dev' into Weblate. 2019-01-29 14:17:45 +01:00
Licaon Kter
93defbf341 Translated using Weblate (Romanian)
Currently translated at 84.1% (322 of 383 strings)
2019-01-29 14:17:45 +01:00
Allan Nordhøy
ca1089da9a Translated using Weblate (Norwegian Bokmål)
Currently translated at 97.7% (374 of 383 strings)
2019-01-29 14:17:44 +01:00
Rex_sa
dd07c7db0e Translated using Weblate (Arabic)
Currently translated at 100.0% (383 of 383 strings)
2019-01-29 14:17:42 +01:00
Almin Agic
dfe932e37a Added translation using Weblate (Bosnian (latin)) 2019-01-29 14:17:38 +01:00
anoy
3ac4899b96 Merge branch 'dev' into patch-1 2019-01-28 21:19:21 +01:00
Ritvik Saraf
86d619be30 merged upstream/dev 2019-01-19 15:48:05 +05:30
Ritvik Saraf
fec7672598 updated extractor for url decryption fix 2019-01-19 15:26:31 +05:30
Ritvik Saraf
559c397b2f more NPE fix 2018-12-25 20:17:56 +05:30
Ritvik Saraf
646698f1ed fixed NPE in soundcloud 2018-12-25 19:59:03 +05:30
Ritvik Saraf
c9b938ae55 readded animations 2018-12-25 15:36:15 +05:30
Ritvik Saraf
990c220fa0 updated extractor 2018-12-23 09:44:42 +05:30
Ritvik Saraf
f19cfb75e6 merged upstream/dev 2018-12-20 08:51:44 +05:30
Ritvik Saraf
ceaacc771d removed jerky animations 2018-12-19 10:58:59 +05:30
Ritvik Saraf
48067e3285 up next text alignment 2018-12-17 10:03:04 +05:30
Ritvik Saraf
222c8fdb62 tablet ui support for comments 2018-12-09 03:21:55 +05:30
Ritvik Saraf
1a62b9a161 removed dislike button, added comment published time 2018-12-08 20:32:28 +05:30
Ritvik Saraf
ccb9bceecc removed unused imports 2018-12-07 08:42:05 +05:30
Ritvik Saraf
c1a67ff1f8 minor scrolling fix and ellipsize fix 2018-12-07 06:45:33 +05:30
Ritvik Saraf
ff90f257cc removed useless log statement 2018-12-04 23:37:02 +05:30
Ritvik Saraf
9b84046865 merged upstream/dev 2018-12-04 23:19:57 +05:30
anoy
5ac17ee6b8 added support for invidio.us links 2018-11-23 19:18:34 +01:00
Ritvik Saraf
fa5896ee5b fixed screen rotation for viewpager 2018-10-19 18:44:03 +05:30
Ritvik Saraf
9fc38b5bb8 improved fling behavior, added tab indicator dots, added next video in related videos 2018-10-17 00:23:02 +05:30
Ritvik Saraf
cf3e53eb71 update notify on dataset change 2018-10-02 21:30:11 +05:30
Ritvik Saraf
b8865e925d added content setting to disable comments 2018-10-02 20:56:14 +05:30
Ritvik Saraf
2e9a860aaa added viewpager. changed from parallaxscrollview to coordinate layout 2018-10-02 20:39:16 +05:30
Ritvik Saraf
e4bef056e6 merged upstream/dev 2018-09-29 15:46:47 +05:30
Ritvik Saraf
803b8eab28 updated extractor version 2018-09-28 05:04:36 +05:30
Ritvik Saraf
08bbfc50ee updated extractor 2018-09-27 23:27:52 +05:30
Ritvik Saraf
4e6722f201 updated extractor and downloader 2018-09-27 04:20:57 +05:30
Ritvik Saraf
a29e2116a7 handling error while loading comments 2018-09-27 00:53:36 +05:30
Ritvik Saraf
515be677a9 no comments 2018-09-24 14:53:43 +05:30
Ritvik Saraf
d694c5f511 smoother transition to comments fragment 2018-09-23 19:45:26 +05:30
Ritvik Saraf
66c753f3a3 changed comments fragment loading animation 2018-09-23 15:22:45 +05:30
Ritvik Saraf
7047b62442 added comments fragment 2018-09-23 07:02:19 +05:30
Ritvik Saraf
5cc73555cd updated extractor version 2018-09-19 05:41:01 +05:30
Ritvik Saraf
219922cd82 added commentsInfo in streamInfo 2018-09-19 05:13:55 +05:30
Ritvik Saraf
08127e5806 added basic/crappy comments support 2018-09-15 17:15:44 +05:30
94 changed files with 5256 additions and 2016 deletions

View File

@@ -16,7 +16,9 @@
<p align="center"><a href="https://newpipe.schabi.org">Website</a> &bull; <a href="https://newpipe.schabi.org/blog/">Blog</a> &bull; <a href="https://newpipe.schabi.org/press/">Press</a></p>
<hr>
<b>WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.</b>
<b>WARNING: THIS IS A BETA VERSION, THEREFORE YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE VIA OUR GITHUB REPOSITORY.</b>
<b>PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.</b>
## Screenshots

View File

@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 19
targetSdkVersion 28
versionCode 71
versionName "0.15.1"
versionCode 730
versionName "0.16.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -57,7 +57,7 @@ dependencies {
exclude module: 'support-annotations'
})
implementation 'com.github.TeamNewPipe:NewPipeExtractor:f7c7b9df1a'
implementation 'com.github.TeamNewPipe:NewPipeExtractor:e072bf6461b295'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.23.0'

View File

@@ -35,12 +35,6 @@
</intent-filter>
</receiver>
<activity
android:name=".player.old.PlayVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/OldVideoPlayerTheme"
tools:ignore="UnusedAttribute"/>
<service
android:name=".player.BackgroundPlayer"
android:exported="false">
@@ -183,6 +177,19 @@
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="www.youtube-nocookie.com"/>
<data android:pathPrefix="/embed/"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="vnd.youtube"/>
<data android:scheme="vnd.youtube.launch"/>
</intent-filter>
@@ -209,6 +216,29 @@
<data android:pathPrefix="/user/"/>
</intent-filter>
<!-- Invidious filter -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="invidio.us"/>
<data android:host="www.invidio.us"/>
<!-- video prefix -->
<data android:pathPrefix="/embed/"/>
<data android:pathPrefix="/watch"/>
<!-- channel prefix -->
<data android:pathPrefix="/channel/"/>
<data android:pathPrefix="/user/"/>
<!-- playlist prefix -->
<data android:pathPrefix="/playlist"/>
</intent-filter>
<!-- Soundcloud filter -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>

View File

@@ -0,0 +1,116 @@
package android.support.design.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.animation.AnimationUtils;
import android.util.AttributeSet;
import android.view.View;
// check this https://github.com/ToDou/appbarlayout-spring-behavior/blob/master/appbarspring/src/main/java/android/support/design/widget/AppBarFlingFixBehavior.java
public final class FlingBehavior extends AppBarLayout.Behavior {
private ValueAnimator mOffsetAnimator;
private static final int MAX_OFFSET_ANIMATION_DURATION = 600; // ms
public FlingBehavior() {
}
public FlingBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
if (dy != 0) {
int val = child.getBottom();
if (val != 0) {
int min, max;
if (dy < 0) {
// We're scrolling down
} else {
// We're scrolling up
if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {
mOffsetAnimator.cancel();
}
min = -child.getUpNestedPreScrollRange();
max = 0;
consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
}
}
}
}
@Override
public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull AppBarLayout child, @NonNull View target, float velocityX, float velocityY) {
if (velocityY != 0) {
if (velocityY < 0) {
// We're flinging down
int val = child.getBottom();
if (val != 0) {
final int targetScroll =
+child.getDownNestedPreScrollRange();
animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY);
}
} else {
// We're flinging up
int val = child.getBottom();
if (val != 0) {
final int targetScroll = -child.getUpNestedPreScrollRange();
if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY);
}
}
}
}
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
final AppBarLayout child, final int offset, float velocity) {
final int distance = Math.abs(getTopBottomOffsetForScrollingSibling() - offset);
final int duration;
velocity = Math.abs(velocity);
if (velocity > 0) {
duration = 3 * Math.round(1000 * (distance / velocity));
} else {
final float distanceRatio = (float) distance / child.getHeight();
duration = (int) ((distanceRatio + 1) * 150);
}
animateOffsetWithDuration(coordinatorLayout, child, offset, duration);
}
private void animateOffsetWithDuration(final CoordinatorLayout coordinatorLayout,
final AppBarLayout child, final int offset, final int duration) {
final int currentOffset = getTopBottomOffsetForScrollingSibling();
if (currentOffset == offset) {
if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {
mOffsetAnimator.cancel();
}
return;
}
if (mOffsetAnimator == null) {
mOffsetAnimator = new ValueAnimator();
mOffsetAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
mOffsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
setHeaderTopBottomOffset(coordinatorLayout, child,
(Integer) animator.getAnimatedValue());
}
});
} else {
mOffsetAnimator.cancel();
}
mOffsetAnimator.setDuration(Math.min(duration, MAX_OFFSET_ANIMATION_DURATION));
mOffsetAnimator.setIntValues(currentOffset, offset);
mOffsetAnimator.start();
}
}

View File

@@ -3,18 +3,24 @@ package org.schabi.newpipe;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.schabi.newpipe.extractor.DownloadRequest;
import org.schabi.newpipe.extractor.DownloadResponse;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.utils.Localization;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
@@ -139,13 +145,16 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
private ResponseBody getBody(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
final Request.Builder requestBuilder = new Request.Builder()
.method("GET", null).url(siteUrl)
.addHeader("User-Agent", USER_AGENT);
.method("GET", null).url(siteUrl);
for (Map.Entry<String, String> header : customProperties.entrySet()) {
requestBuilder.addHeader(header.getKey(), header.getValue());
}
if (!customProperties.containsKey("User-Agent")) {
requestBuilder.header("User-Agent", USER_AGENT);
}
if (!TextUtils.isEmpty(mCookies)) {
requestBuilder.addHeader("Cookie", mCookies);
}
@@ -177,4 +186,96 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
public String download(String siteUrl) throws IOException, ReCaptchaException {
return download(siteUrl, Collections.emptyMap());
}
}
@Override
public DownloadResponse get(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
final Request.Builder requestBuilder = new Request.Builder()
.method("GET", null).url(siteUrl);
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
// set custom headers in request
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
for(String value : pair.getValue()){
requestBuilder.addHeader(pair.getKey(), value);
}
}
if (!requestHeaders.containsKey("User-Agent")) {
requestBuilder.header("User-Agent", USER_AGENT);
}
if (!TextUtils.isEmpty(mCookies)) {
requestBuilder.addHeader("Cookie", mCookies);
}
final Request okRequest = requestBuilder.build();
final Response response = client.newCall(okRequest).execute();
final ResponseBody body = response.body();
if (response.code() == 429) {
throw new ReCaptchaException("reCaptcha Challenge requested");
}
if (body == null) {
response.close();
return null;
}
return new DownloadResponse(body.string(), response.headers().toMultimap());
}
@Override
public DownloadResponse get(String siteUrl) throws IOException, ReCaptchaException {
return get(siteUrl, DownloadRequest.emptyRequest);
}
@Override
public DownloadResponse post(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
if(null == requestHeaders.get("Content-Type") || requestHeaders.get("Content-Type").isEmpty()){
// content type header is required. maybe throw an exception here
return null;
}
String contentType = requestHeaders.get("Content-Type").get(0);
RequestBody okRequestBody = null;
if(null != request.getRequestBody()){
okRequestBody = RequestBody.create(MediaType.parse(contentType), request.getRequestBody());
}
final Request.Builder requestBuilder = new Request.Builder()
.method("POST", okRequestBody).url(siteUrl);
// set custom headers in request
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
for(String value : pair.getValue()){
requestBuilder.addHeader(pair.getKey(), value);
}
}
if (!requestHeaders.containsKey("User-Agent")) {
requestBuilder.header("User-Agent", USER_AGENT);
}
if (!TextUtils.isEmpty(mCookies)) {
requestBuilder.addHeader("Cookie", mCookies);
}
final Request okRequest = requestBuilder.build();
final Response response = client.newCall(okRequest).execute();
final ResponseBody body = response.body();
if (response.code() == 429) {
throw new ReCaptchaException("reCaptcha Challenge requested");
}
if (body == null) {
response.close();
return null;
}
return new DownloadResponse(body.string(), response.headers().toMultimap());
}
}

View File

@@ -0,0 +1,73 @@
package org.schabi.newpipe.fragments.detail;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class TabAdaptor extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
private final FragmentManager fragmentManager;
public TabAdaptor(FragmentManager fm) {
super(fm);
this.fragmentManager = fm;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void clearAllItems() {
mFragmentList.clear();
mFragmentTitleList.clear();
}
public void removeItem(int position){
mFragmentList.remove(position == 0 ? 0 : position - 1);
mFragmentTitleList.remove(position == 0 ? 0 : position - 1);
}
public void updateItem(int position, Fragment fragment){
mFragmentList.set(position, fragment);
}
public void updateItem(String title, Fragment fragment){
int index = mFragmentTitleList.indexOf(title);
if(index != -1){
updateItem(index, fragment);
}
}
@Override
public int getItemPosition(Object object) {
if (mFragmentList.contains(object)) return mFragmentList.indexOf(object);
else return POSITION_NONE;
}
public void notifyDataSetUpdate(){
notifyDataSetChanged();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
}
}

View File

@@ -22,6 +22,7 @@ import android.view.View;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment;
@@ -220,6 +221,13 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
}
});
infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<CommentsInfoItem>() {
@Override
public void selected(CommentsInfoItem selectedItem) {
onItemSelected(selectedItem);
}
});
itemsList.clearOnScrollListeners();
itemsList.addOnScrollListener(new OnScrollBelowItemsListener() {
@Override

View File

@@ -233,10 +233,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
openRssFeed();
break;
case R.id.menu_item_openInBrowser:
openUrlInBrowser(url);
openUrlInBrowser(currentInfo.getOriginalUrl());
break;
case R.id.menu_item_share:
shareUrl(name, url);
shareUrl(name, currentInfo.getOriginalUrl());
break;
default:
return super.onOptionsItemSelected(item);

View File

@@ -0,0 +1,149 @@
package org.schabi.newpipe.fragments.list.comments;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
private CompositeDisposable disposables = new CompositeDisposable();
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private boolean mIsVisibleToUser = false;
public static CommentsFragment getInstance(int serviceId, String url, String name) {
CommentsFragment instance = new CommentsFragment();
instance.setInitialData(serviceId, url, name);
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
mIsVisibleToUser = isVisibleToUser;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_comments, container, false);
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposables != null) disposables.clear();
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
return ExtractorHelper.getMoreCommentItems(serviceId, currentInfo, currentNextPageUrl);
}
@Override
protected Single<CommentsInfo> loadResult(boolean forceLoad) {
return ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
}
@Override
public void handleResult(@NonNull CommentsInfo result) {
super.handleResult(result);
AnimationUtils.slideUp(getView(),120, 96, 0.06f);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
if (disposables != null) disposables.clear();
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(),
UserAction.REQUESTED_COMMENTS,
NewPipe.getNameOfService(serviceId),
"Get next page of: " + url,
R.string.general_error);
}
}
/*//////////////////////////////////////////////////////////////////////////
// OnError
//////////////////////////////////////////////////////////////////////////*/
@Override
protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true;
hideLoading();
showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments);
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setTitle(String title) {
return;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
return;
}
@Override
protected boolean isGridLayout() {
return false;
}
}

View File

@@ -39,6 +39,7 @@ import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.search.SearchInfo;
import org.schabi.newpipe.util.FireTvUtils;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager;
@@ -104,8 +105,13 @@ public class SearchFragment
// this three represet the current search query
@State
protected String searchString;
/**
* No content filter should add like contentfilter = all
* be aware of this when implementing an extractor.
*/
@State
protected String[] contentFilter;
protected String[] contentFilter = new String[0];
@State
protected String sortFilter;
@@ -335,7 +341,7 @@ public class SearchFragment
|| (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
search(!TextUtils.isEmpty(searchString)
? searchString
: searchEditText.getText().toString(), new String[0], "");
: searchEditText.getText().toString(), this.contentFilter, "");
} else {
if (searchEditText != null) {
searchEditText.setText("");
@@ -449,6 +455,9 @@ public class SearchFragment
if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) {
showSuggestionsPanel();
}
if(FireTvUtils.isFireTv()){
showKeyboardSearch();
}
});
searchEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
@@ -499,7 +508,9 @@ public class SearchFragment
if (DEBUG) {
Log.d(TAG, "onEditorAction() called with: v = [" + v + "], actionId = [" + actionId + "], event = [" + event + "]");
}
if (event != null
if(actionId == EditorInfo.IME_ACTION_PREVIOUS){
hideKeyboardSearch();
} else if (event != null
&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|| event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
search(searchEditText.getText().toString(), new String[0], "");
@@ -541,7 +552,7 @@ public class SearchFragment
if (searchEditText.requestFocus()) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT);
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
}
}
@@ -551,8 +562,7 @@ public class SearchFragment
InputMethodManager imm = (InputMethodManager) activity.getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
searchEditText.clearFocus();
}
@@ -736,6 +746,7 @@ public class SearchFragment
@Override
protected void loadMoreItems() {
if(nextPageUrl == null || nextPageUrl.isEmpty()) return;
isLoading.set(true);
showListFooter(true);
if (searchDisposable != null) searchDisposable.dispose();

View File

@@ -0,0 +1,208 @@
package org.schabi.newpipe.fragments.list.videos;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.Switch;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.RelatedStreamInfo;
import java.io.Serializable;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInfo> implements SharedPreferences.OnSharedPreferenceChangeListener{
private CompositeDisposable disposables = new CompositeDisposable();
private RelatedStreamInfo relatedStreamInfo;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private Switch aSwitch;
private boolean mIsVisibleToUser = false;
public static RelatedVideosFragment getInstance(StreamInfo info) {
RelatedVideosFragment instance = new RelatedVideosFragment();
instance.setInitialData(info);
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
mIsVisibleToUser = isVisibleToUser;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_related_streams, container, false);
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposables != null) disposables.clear();
}
protected View getListHeader(){
if(relatedStreamInfo != null && relatedStreamInfo.getNextStream() != null){
headerRootLayout = activity.getLayoutInflater().inflate(R.layout.related_streams_header, itemsList, false);
aSwitch = headerRootLayout.findViewById(R.id.autoplay_switch);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
Boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
aSwitch.setChecked(autoplay);
aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
prefEdit.putBoolean(getString(R.string.auto_queue_key), b);
prefEdit.apply();
}
});
return headerRootLayout;
}else{
return null;
}
}
@Override
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
return Single.fromCallable(() -> ListExtractor.InfoItemsPage.emptyPage());
}
@Override
protected Single<RelatedStreamInfo> loadResult(boolean forceLoad) {
return Single.fromCallable(() -> relatedStreamInfo);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
if(null != headerRootLayout) headerRootLayout.setVisibility(View.INVISIBLE);
}
@Override
public void handleResult(@NonNull RelatedStreamInfo result) {
super.handleResult(result);
if(null != headerRootLayout) headerRootLayout.setVisibility(View.VISIBLE);
AnimationUtils.slideUp(getView(),120, 96, 0.06f);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
if (disposables != null) disposables.clear();
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(),
UserAction.REQUESTED_STREAM,
NewPipe.getNameOfService(serviceId),
"Get next page of: " + url,
R.string.general_error);
}
}
/*//////////////////////////////////////////////////////////////////////////
// OnError
//////////////////////////////////////////////////////////////////////////*/
@Override
protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true;
hideLoading();
showSnackBarError(exception, UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, R.string.general_error);
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setTitle(String title) {
return;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
return;
}
private void setInitialData(StreamInfo info) {
super.setInitialData(info.getServiceId(), info.getUrl(), info.getName());
if(this.relatedStreamInfo == null) this.relatedStreamInfo = RelatedStreamInfo.getInfo(info);
}
private static final String INFO_KEY = "related_info_key";
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(INFO_KEY, relatedStreamInfo);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedState) {
super.onRestoreInstanceState(savedState);
if (savedState != null) {
Serializable serializable = savedState.getSerializable(INFO_KEY);
if(serializable instanceof RelatedStreamInfo){
this.relatedStreamInfo = (RelatedStreamInfo) serializable;
}
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
Boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
if(null != aSwitch) aSwitch.setChecked(autoplay);
}
@Override
protected boolean isGridLayout() {
return false;
}
}

View File

@@ -10,10 +10,13 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
@@ -50,6 +53,7 @@ public class InfoItemBuilder {
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener;
private OnClickGesture<CommentsInfoItem> onCommentsSelectedListener;
public InfoItemBuilder(Context context) {
this.context = context;
@@ -73,6 +77,8 @@ public class InfoItemBuilder {
return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) : new ChannelInfoItemHolder(this, parent);
case PLAYLIST:
return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) : new PlaylistInfoItemHolder(this, parent);
case COMMENT:
return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent);
default:
Log.e(TAG, "Trollolo");
throw new RuntimeException("InfoType not expected = " + infoType.name());
@@ -111,4 +117,12 @@ public class InfoItemBuilder {
this.onPlaylistSelectedListener = listener;
}
public OnClickGesture<CommentsInfoItem> getOnCommentsSelectedListener() {
return onCommentsSelectedListener;
}
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> onCommentsSelectedListener) {
this.onCommentsSelectedListener = onCommentsSelectedListener;
}
}

View File

@@ -9,10 +9,13 @@ import android.view.ViewGroup;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
@@ -63,6 +66,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
private static final int GRID_PLAYLIST_HOLDER_TYPE = 0x302;
private static final int MINI_COMMENT_HOLDER_TYPE = 0x400;
private static final int COMMENT_HOLDER_TYPE = 0x401;
private final InfoItemBuilder infoItemBuilder;
private final ArrayList<InfoItem> infoItemList;
@@ -98,6 +103,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
infoItemBuilder.setOnPlaylistSelectedListener(listener);
}
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> listener) {
infoItemBuilder.setOnCommentsSelectedListener(listener);
}
public void useMiniItemVariants(boolean useMiniVariant) {
this.useMiniVariant = useMiniVariant;
}
@@ -223,6 +232,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return useGridVariant ? GRID_CHANNEL_HOLDER_TYPE : useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
case PLAYLIST:
return useGridVariant ? GRID_PLAYLIST_HOLDER_TYPE : useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
case COMMENT:
return useMiniVariant ? MINI_COMMENT_HOLDER_TYPE : COMMENT_HOLDER_TYPE;
default:
Log.e(TAG, "Trollolo");
return -1;
@@ -231,7 +242,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
if (DEBUG) Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
if (DEBUG)
Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
switch (type) {
case HEADER_TYPE:
return new HFHolder(header);
@@ -255,6 +267,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
case GRID_PLAYLIST_HOLDER_TYPE:
return new PlaylistGridInfoItemHolder(infoItemBuilder, parent);
case MINI_COMMENT_HOLDER_TYPE:
return new CommentsMiniInfoItemHolder(infoItemBuilder, parent);
case COMMENT_HOLDER_TYPE:
return new CommentsInfoItemHolder(infoItemBuilder, parent);
default:
Log.e(TAG, "Trollolo");
return new FallbackViewHolder(new View(parent.getContext()));

View File

@@ -0,0 +1,53 @@
package org.schabi.newpipe.info_list.holder;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.util.Localization;
/*
* Created by Christian Schabesberger on 12.02.17.
*
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* ChannelInfoItemHolder .java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
public final TextView itemTitleView;
public CommentsInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_comments_item, parent);
itemTitleView = itemView.findViewById(R.id.itemTitleView);
}
@Override
public void updateFromItem(final InfoItem infoItem) {
super.updateFromItem(infoItem);
if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
itemTitleView.setText(item.getAuthorName());
}
}

View File

@@ -0,0 +1,99 @@
package org.schabi.newpipe.info_list.holder;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.NavigationHelper;
import de.hdodenhof.circleimageview.CircleImageView;
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
public final CircleImageView itemThumbnailView;
private final TextView itemContentView;
private final TextView itemLikesCountView;
private final TextView itemDislikesCountView;
private final TextView itemPublishedTime;
private static final int commentDefaultLines = 2;
private static final int commentExpandedLines = 1000;
CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view);
itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view);
itemPublishedTime = itemView.findViewById(R.id.itemPublishedTime);
itemContentView = itemView.findViewById(R.id.itemCommentContentView);
}
public CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
this(infoItemBuilder, R.layout.list_comments_mini_item, parent);
}
@Override
public void updateFromItem(final InfoItem infoItem) {
if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
itemBuilder.getImageLoader()
.displayImage(item.getAuthorThumbnail(),
itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
itemThumbnailView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
NavigationHelper.openChannelFragment(
activity.getSupportFragmentManager(),
item.getServiceId(),
item.getAuthorEndpoint(),
item.getAuthorName());
} catch (Exception e) {
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
}
}
});
// ellipsize if not already ellipsized
if (null == itemContentView.getEllipsize()) {
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
itemContentView.setMaxLines(commentDefaultLines);
}
itemContentView.setText(item.getCommentText());
if (null != item.getLikeCount()) {
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
}
itemPublishedTime.setText(item.getPublishedTime());
itemView.setOnClickListener(view -> {
toggleEllipsize(item.getCommentText());
if (itemBuilder.getOnCommentsSelectedListener() != null) {
itemBuilder.getOnCommentsSelectedListener().selected(item);
}
});
}
private void toggleEllipsize(String text) {
// toggle ellipsize
if (null == itemContentView.getEllipsize()) {
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
itemContentView.setMaxLines(commentDefaultLines);
} else {
itemContentView.setEllipsize(null);
itemContentView.setMaxLines(commentExpandedLines);
}
}
}

View File

@@ -147,11 +147,16 @@ public class SubscriptionService {
}
private boolean isSubscriptionUpToDate(final ChannelInfo info, final SubscriptionEntity entity) {
return info.getUrl().equals(entity.getUrl()) &&
return equalsAndNotNull(info.getUrl(), entity.getUrl()) &&
info.getServiceId() == entity.getServiceId() &&
info.getName().equals(entity.getName()) &&
info.getAvatarUrl().equals(entity.getAvatarUrl()) &&
info.getDescription().equals(entity.getDescription()) &&
equalsAndNotNull(info.getAvatarUrl(), entity.getAvatarUrl()) &&
equalsAndNotNull(info.getDescription(), entity.getDescription()) &&
info.getSubscriberCount() == entity.getSubscriberCount();
}
private boolean equalsAndNotNull(final Object o1, final Object o2) {
return (o1 != null && o2 != null)
&& o1.equals(o2);
}
}

View File

@@ -626,6 +626,7 @@ public final class PopupVideoPlayer extends Service {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
if (playerImpl == null) return;
// rebuild notification here since remote view does not release bitmaps,
// causing memory leaks
resetNotification();

View File

@@ -131,7 +131,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
private void onAudioFocusLossCanDuck() {
Log.d(TAG, "onAudioFocusLossCanDuck() called");
// Set the volume to 1/10 on ducking
animateAudio(player.getVolume(), DUCK_AUDIO_TO);
player.setVolume(DUCK_AUDIO_TO);
}
private void animateAudio(final float from, final float to) {

View File

@@ -45,7 +45,9 @@ import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MOD
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.*;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
public class PlayerHelper {
private PlayerHelper() {}

View File

@@ -1,7 +1,9 @@
package org.schabi.newpipe.player.playback;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import org.schabi.newpipe.player.BasePlayer;
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
@@ -54,6 +56,12 @@ public class BasePlayerMediaSession implements MediaSessionCallback {
.setTitle(item.getTitle())
.setSubtitle(item.getUploader());
// set additional metadata for A2DP/AVRCP
Bundle additionalMetadata = new Bundle();
additionalMetadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, item.getUploader());
additionalMetadata.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, item.getDuration());
descriptionBuilder.setExtras(additionalMetadata);
final Uri thumbnailUri = Uri.parse(item.getThumbnailUrl());
if (thumbnailUri != null) descriptionBuilder.setIconUri(thumbnailUri);

View File

@@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.helper.PlayerDataSource;
import org.schabi.newpipe.player.helper.PlayerHelper;
@@ -93,15 +94,17 @@ public class VideoPlaybackResolver implements PlaybackResolver {
// Below are auxiliary media sources
// Create subtitle sources
for (final SubtitlesStream subtitle : info.getSubtitles()) {
final String mimeType = PlayerHelper.subtitleMimeTypesOf(subtitle.getFormat());
if (mimeType == null) continue;
if(info.getSubtitles() != null) {
for (final SubtitlesStream subtitle : info.getSubtitles()) {
final String mimeType = PlayerHelper.subtitleMimeTypesOf(subtitle.getFormat());
if (mimeType == null) continue;
final Format textFormat = Format.createTextSampleFormat(null, mimeType,
SELECTION_FLAG_AUTOSELECT, PlayerHelper.captionLanguageOf(context, subtitle));
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
.createMediaSource(Uri.parse(subtitle.getURL()), textFormat, TIME_UNSET);
mediaSources.add(textSource);
final Format textFormat = Format.createTextSampleFormat(null, mimeType,
SELECTION_FLAG_AUTOSELECT, PlayerHelper.captionLanguageOf(context, subtitle));
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
.createMediaSource(Uri.parse(subtitle.getURL()), textFormat, TIME_UNSET);
mediaSources.add(textSource);
}
}
if (mediaSources.size() == 1) {

View File

@@ -15,6 +15,7 @@ public enum UserAction {
REQUESTED_CHANNEL("requested channel"),
REQUESTED_PLAYLIST("requested playlist"),
REQUESTED_KIOSK("requested kiosk"),
REQUESTED_COMMENTS("requested comments"),
DELETE_FROM_HISTORY("delete from history"),
PLAY_STREAM("Play stream");

View File

@@ -25,6 +25,7 @@ import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.res.ColorStateList;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.Log;
@@ -363,4 +364,24 @@ public class AnimationUtils {
}).start();
}
}
public static void slideUp(final View view,
long duration,
long delay,
@FloatRange(from = 0.0f, to = 1.0f) float translationPercent) {
int translationY = (int) (view.getResources().getDisplayMetrics().heightPixels *
(translationPercent));
view.animate().setListener(null).cancel();
view.setAlpha(0f);
view.setTranslationY(translationY);
view.setVisibility(View.VISIBLE);
view.animate()
.alpha(1f)
.translationY(0)
.setStartDelay(delay)
.setDuration(duration)
.setInterpolator(new FastOutSlowInInterpolator())
.start();
}
}

View File

@@ -29,10 +29,12 @@ import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
@@ -46,6 +48,7 @@ import org.schabi.newpipe.report.UserAction;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Collections;
import java.util.List;
import io.reactivex.Maybe;
@@ -60,7 +63,7 @@ public final class ExtractorHelper {
}
private static void checkServiceId(int serviceId) {
if(serviceId == Constants.NO_SERVICE_ID) {
if (serviceId == Constants.NO_SERVICE_ID) {
throw new IllegalArgumentException("serviceId is NO_SERVICE_ID");
}
}
@@ -95,17 +98,20 @@ public final class ExtractorHelper {
public static Single<List<String>> suggestionsFor(final int serviceId,
final String query) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
NewPipe.getService(serviceId)
.getSuggestionExtractor()
.suggestionList(query));
return Single.fromCallable(() -> {
SuggestionExtractor extractor = NewPipe.getService(serviceId)
.getSuggestionExtractor();
return extractor != null
? extractor.suggestionList(query)
: Collections.emptyList();
});
}
public static Single<StreamInfo> getStreamInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.STREAM, Single.fromCallable(() ->
StreamInfo.getInfo(NewPipe.getService(serviceId), url)));
}
@@ -113,29 +119,45 @@ public final class ExtractorHelper {
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.CHANNEL, Single.fromCallable(() ->
ChannelInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<InfoItemsPage> getMoreChannelItems(final int serviceId,
final String url,
final String nextStreamsUrl) {
final String url,
final String nextStreamsUrl) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
}
public static Single<CommentsInfo> getCommentsInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.COMMENT, Single.fromCallable(() ->
CommentsInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<InfoItemsPage> getMoreCommentItems(final int serviceId,
final CommentsInfo info,
final String nextPageUrl) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
CommentsInfo.getMoreItems(NewPipe.getService(serviceId), info, nextPageUrl));
}
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() ->
PlaylistInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<InfoItemsPage> getMorePlaylistItems(final int serviceId,
final String url,
final String nextStreamsUrl) {
final String url,
final String nextStreamsUrl) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
@@ -144,7 +166,7 @@ public final class ExtractorHelper {
public static Single<KioskInfo> getKioskInfo(final int serviceId,
final String url,
boolean forceLoad) {
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() ->
KioskInfo.getInfo(NewPipe.getService(serviceId), url)));
}
@@ -168,16 +190,17 @@ public final class ExtractorHelper {
private static <I extends Info> Single<I> checkCache(boolean forceLoad,
int serviceId,
String url,
InfoItem.InfoType infoType,
Single<I> loadFromNetwork) {
checkServiceId(serviceId);
loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info));
loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info, infoType));
Single<I> load;
if (forceLoad) {
cache.removeInfo(serviceId, url);
cache.removeInfo(serviceId, url, infoType);
load = loadFromNetwork;
} else {
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url),
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url, infoType),
loadFromNetwork.toMaybe())
.firstElement() //Take the first valid
.toSingle();
@@ -189,20 +212,20 @@ public final class ExtractorHelper {
/**
* Default implementation uses the {@link InfoCache} to get cached results
*/
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) {
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url, InfoItem.InfoType infoType) {
checkServiceId(serviceId);
return Maybe.defer(() -> {
//noinspection unchecked
I info = (I) cache.getFromKey(serviceId, url);
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
//noinspection unchecked
I info = (I) cache.getFromKey(serviceId, url, infoType);
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
// Only return info if it's not null (it is cached)
if (info != null) {
return Maybe.just(info);
}
// Only return info if it's not null (it is cached)
if (info != null) {
return Maybe.just(info);
}
return Maybe.empty();
});
return Maybe.empty();
});
}
/**

View File

@@ -0,0 +1,10 @@
package org.schabi.newpipe.util;
import org.schabi.newpipe.App;
public class FireTvUtils {
public static boolean isFireTv(){
final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv";
return App.getApp().getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV);
}
}

View File

@@ -26,6 +26,7 @@ import android.util.Log;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.InfoItem;
import java.util.Map;
@@ -52,27 +53,27 @@ public final class InfoCache {
}
@Nullable
public Info getFromKey(int serviceId, @NonNull String url) {
public Info getFromKey(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) {
if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
synchronized (lruCache) {
return getInfo(keyOf(serviceId, url));
return getInfo(keyOf(serviceId, url, infoType));
}
}
public void putInfo(int serviceId, @NonNull String url, @NonNull Info info) {
public void putInfo(int serviceId, @NonNull String url, @NonNull Info info, @NonNull InfoItem.InfoType infoType) {
if (DEBUG) Log.d(TAG, "putInfo() called with: info = [" + info + "]");
final long expirationMillis = ServiceHelper.getCacheExpirationMillis(info.getServiceId());
synchronized (lruCache) {
final CacheData data = new CacheData(info, expirationMillis);
lruCache.put(keyOf(serviceId, url), data);
lruCache.put(keyOf(serviceId, url, infoType), data);
}
}
public void removeInfo(int serviceId, @NonNull String url) {
public void removeInfo(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) {
if (DEBUG) Log.d(TAG, "removeInfo() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
synchronized (lruCache) {
lruCache.remove(keyOf(serviceId, url));
lruCache.remove(keyOf(serviceId, url, infoType));
}
}
@@ -98,8 +99,8 @@ public final class InfoCache {
}
@NonNull
private static String keyOf(final int serviceId, @NonNull final String url) {
return serviceId + url;
private static String keyOf(final int serviceId, @NonNull final String url, @NonNull InfoItem.InfoType infoType) {
return serviceId + url + infoType.toString();
}
private static void removeStaleCache() {

View File

@@ -31,6 +31,8 @@ public class KioskTranslator {
return c.getString(R.string.top_50);
case "New & hot":
return c.getString(R.string.new_and_hot);
case "conferences":
return c.getString(R.string.conferences);
default:
return kioskId;
}
@@ -44,6 +46,8 @@ public class KioskTranslator {
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
case "New & hot":
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
case "conferences":
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
default:
return 0;
}

View File

@@ -33,6 +33,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
import org.schabi.newpipe.local.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
@@ -309,6 +310,18 @@ public class NavigationHelper {
.commit();
}
public static void openCommentsFragment(
FragmentManager fragmentManager,
int serviceId,
String url,
String name) {
if (name == null) name = "";
fragmentManager.beginTransaction().setCustomAnimations(R.anim.switch_service_in, R.anim.switch_service_out)
.replace(R.id.fragment_holder, CommentsFragment.getInstance(serviceId, url, name))
.addToBackStack(null)
.commit();
}
public static void openPlaylistFragment(FragmentManager fragmentManager,
int serviceId,
String url,

View File

@@ -0,0 +1,41 @@
package org.schabi.newpipe.util;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RelatedStreamInfo extends ListInfo<InfoItem> {
private StreamInfoItem nextStream;
public RelatedStreamInfo(int serviceId, ListLinkHandler listUrlIdHandler, String name) {
super(serviceId, listUrlIdHandler, name);
}
public static RelatedStreamInfo getInfo(StreamInfo info) {
ListLinkHandler handler = new ListLinkHandler(info.getOriginalUrl(), info.getUrl(), info.getId(), Collections.emptyList(), null);
RelatedStreamInfo relatedStreamInfo = new RelatedStreamInfo(info.getServiceId(), handler, info.getName());
List<InfoItem> streams = new ArrayList<>();
if(info.getNextVideo() != null){
streams.add(info.getNextVideo());
}
streams.addAll(info.getRelatedStreams());
relatedStreamInfo.setRelatedItems(streams);
relatedStreamInfo.setNextStream(info.getNextVideo());
return relatedStreamInfo;
}
public StreamInfoItem getNextStream() {
return nextStream;
}
public void setNextStream(StreamInfoItem nextStream) {
this.nextStream = nextStream;
}
}

View File

@@ -24,9 +24,11 @@ public class ServiceHelper {
case 0:
return R.drawable.place_holder_youtube;
case 1:
return R.drawable.place_holder_circle;
return R.drawable.place_holder_cloud;
case 2:
return R.drawable.place_holder_gadse;
default:
return R.drawable.service;
return R.drawable.place_holder_circle;
}
}
@@ -38,6 +40,8 @@ public class ServiceHelper {
case "playlists": return c.getString(R.string.playlists);
case "tracks": return c.getString(R.string.tracks);
case "users": return c.getString(R.string.users);
case "conferences" : return c.getString(R.string.conferences);
case "events" : return c.getString(R.string.events);
default: return filter;
}
}

View File

@@ -28,7 +28,8 @@ import io.reactivex.schedulers.Schedulers;
import us.shandian.giga.util.Utility;
/**
* A list adapter for a list of {@link Stream streams}, currently supporting {@link VideoStream} and {@link AudioStream}.
* A list adapter for a list of {@link Stream streams},
* currently supporting {@link VideoStream}, {@link AudioStream} and {@link SubtitlesStream}
*/
public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseAdapter {
private final Context context;
@@ -110,7 +111,10 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
}
}
} else if (stream instanceof AudioStream) {
qualityString = ((AudioStream) stream).getAverageBitrate() + "kbps";
AudioStream audioStream = ((AudioStream) stream);
qualityString = audioStream.getAverageBitrate() > 0
? audioStream.getAverageBitrate() + "kbps"
: audioStream.getFormat().getName();
} else if (stream instanceof SubtitlesStream) {
qualityString = ((SubtitlesStream) stream).getDisplayLanguageName();
if (((SubtitlesStream) stream).isAutoGenerated()) {
@@ -154,8 +158,10 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
private final long[] streamSizes;
private final String unknownSize;
public StreamSizeWrapper(List<T> streamsList, Context context) {
this.streamsList = streamsList;
public StreamSizeWrapper(List<T> sL, Context context) {
this.streamsList = sL != null
? sL
: Collections.emptyList();
this.streamSizes = new long[streamsList.size()];
this.unknownSize = context == null ? "--.-" : context.getString(R.string.unknown_content);

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