Compare commits

..

2594 Commits

Author SHA1 Message Date
Christian Schabesberger
a0f74e715a fix bugreport for kiosk 2018-04-01 21:54:00 +02:00
Christian Schabesberger
c13e761c3f remove global ip range label 2018-04-01 19:58:07 +02:00
Heimen Stoffels
d41e3bb41e Translated using Weblate (Dutch)
Currently translated at 100.0% (354 of 354 strings)
2018-04-01 16:43:09 +02:00
Weblate
4160bbb8c4 Merge remote-tracking branch 'origin/dev' into dev 2018-04-01 15:38:23 +02:00
Veli Tasalı
404a20f280 Translated using Weblate (Turkish)
Currently translated at 99.4% (352 of 354 strings)
2018-04-01 15:38:23 +02:00
se7entime
2241146b9f Translated using Weblate (Indonesian)
Currently translated at 89.2% (316 of 354 strings)
2018-04-01 15:38:20 +02:00
Christian Schabesberger
bcb26c5721 move on to version 0.13.1 2018-04-01 15:29:57 +02:00
Christian Schabesberger
a681d8c1ba Merge pull request #1227 from TeamNewPipe/removebeta
remove beta
2018-04-01 15:28:49 +02:00
cozyplanes
0515b74f75 Translated using Weblate (Korean)
Currently translated at 100.0% (354 of 354 strings)
2018-04-01 13:40:13 +02:00
Veli Tasalı
7eeb96d88e Translated using Weblate (Turkish)
Currently translated at 99.1% (351 of 354 strings)
2018-03-31 18:01:21 +02:00
se7entime
5b6c73ef06 Translated using Weblate (Indonesian)
Currently translated at 89.5% (317 of 354 strings)
2018-03-31 15:30:26 +02:00
se7entime
c70b866d16 Translated using Weblate (Indonesian)
Currently translated at 87.2% (309 of 354 strings)
2018-03-31 15:28:10 +02:00
se7entime
b84f2874dc Translated using Weblate (Indonesian)
Currently translated at 87.2% (309 of 354 strings)
2018-03-31 15:28:03 +02:00
se7entime
c372b5529b Translated using Weblate (Indonesian)
Currently translated at 80.5% (285 of 354 strings)
2018-03-31 15:25:16 +02:00
se7entime
a43156c38d Translated using Weblate (Indonesian)
Currently translated at 74.5% (264 of 354 strings)
2018-03-31 15:22:37 +02:00
se7entime
a15112febc Translated using Weblate (Indonesian)
Currently translated at 68.9% (244 of 354 strings)
2018-03-31 15:19:45 +02:00
se7entime
1c6a677a39 Translated using Weblate (Indonesian)
Currently translated at 67.7% (240 of 354 strings)
2018-03-31 15:18:34 +02:00
se7entime
9bf749a2c8 Translated using Weblate (Indonesian)
Currently translated at 65.5% (232 of 354 strings)
2018-03-31 15:15:16 +02:00
se7entime
f6c9d9df20 Translated using Weblate (Indonesian)
Currently translated at 57.3% (203 of 354 strings)
2018-03-31 15:04:54 +02:00
se7entime
5386e0ded9 Translated using Weblate (Indonesian)
Currently translated at 56.7% (201 of 354 strings)
2018-03-31 15:04:27 +02:00
se7entime
8fab405a3a Translated using Weblate (Indonesian)
Currently translated at 55.0% (195 of 354 strings)
2018-03-31 15:03:32 +02:00
se7entime
ee409f3ca9 Translated using Weblate (Indonesian)
Currently translated at 49.7% (176 of 354 strings)
2018-03-31 15:00:23 +02:00
Weblate
bda9beacaa Merge remote-tracking branch 'origin/dev' into dev 2018-03-31 14:59:25 +02:00
Veli Tasalı
5d8c7e5733 Translated using Weblate (Turkish)
Currently translated at 96.8% (343 of 354 strings)
2018-03-31 14:59:24 +02:00
Stnby
a68c763125 Translated using Weblate (Lithuanian)
Currently translated at 87.8% (311 of 354 strings)
2018-03-31 14:59:23 +02:00
se7entime
31ac89d9d6 Translated using Weblate (Indonesian)
Currently translated at 49.4% (175 of 354 strings)
2018-03-31 14:59:22 +02:00
se7entime
8b258cbbe4 Translated using Weblate (Indonesian)
Currently translated at 47.7% (169 of 354 strings)
2018-03-31 14:55:56 +02:00
se7entime
53676fc0fd Translated using Weblate (Indonesian)
Currently translated at 47.1% (167 of 354 strings)
2018-03-31 14:53:54 +02:00
Christian Schabesberger
42c561af9e update build tools to 27.0.3 2018-03-30 18:45:27 +02:00
Christian Schabesberger
fae777c14c make service items in drawer be dynamicly generated 2018-03-30 18:41:11 +02:00
Christian Schabesberger
1af6dc614a remove global ip range label 2018-03-30 14:46:26 +02:00
Christian Schabesberger
2986004638 remove entry points in three dot menu in main screen 2018-03-30 11:52:05 +02:00
Christian Schabesberger
d6f7b4706b remove beta build 2018-03-30 11:09:07 +02:00
Christian Schabesberger
b40dd3e5c0 update gradle 2018-03-30 10:58:32 +02:00
Schabi
2f4097ca9d Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2018-03-28 09:58:18 +02:00
Schabi
c8a91fbb25 add note to check if bugs exist in latest version 2018-03-28 09:58:09 +02:00
Víctor Manuel Tapia Ramírez
0ec259a5fc Translated using Weblate (Spanish)
Currently translated at 100.0% (354 of 354 strings)
2018-03-28 09:50:20 +02:00
Weblate
2fda99bdb7 Merge remote-tracking branch 'origin/dev' into dev 2018-03-28 05:36:47 +02:00
nautilusx
1bb4ac4e9c Translated using Weblate (German)
Currently translated at 95.7% (339 of 354 strings)
2018-03-28 05:36:45 +02:00
MORTI
f376b98c09 Translated using Weblate (French)
Currently translated at 96.3% (341 of 354 strings)
2018-03-28 05:36:41 +02:00
Christian Schabesberger
7382fdb2d2 Merge pull request #1217 from Grammost/patch-1
Fix broken Librepay link in README.md
2018-03-27 11:53:08 +02:00
Edwar Tikhonov
aead9592cf Translated using Weblate (Russian)
Currently translated at 94.9% (336 of 354 strings)
2018-03-27 11:39:53 +02:00
MORTI
bedacf29d9 Translated using Weblate (French)
Currently translated at 96.0% (340 of 354 strings)
2018-03-27 04:49:28 +02:00
anonymous
570e9a8307 Translated using Weblate (French)
Currently translated at 89.2% (316 of 354 strings)
2018-03-27 01:15:17 +02:00
justanidea
fcb94ec603 Translated using Weblate (French)
Currently translated at 88.9% (315 of 354 strings)
2018-03-27 01:13:44 +02:00
anonymous
69886ed58b Translated using Weblate (French)
Currently translated at 88.7% (314 of 354 strings)
2018-03-27 01:13:05 +02:00
MORTI
798235cd21 Translated using Weblate (French)
Currently translated at 88.4% (313 of 354 strings)
2018-03-27 01:12:25 +02:00
Grammost
b38b6b6f35 Update README.md 2018-03-26 15:10:03 +00:00
Grammost
2dba13c52e Fix broken Librepay link in README.md 2018-03-26 14:49:59 +00:00
ezjerry liao
ff366cb2c5 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (354 of 354 strings)
2018-03-26 11:33:45 +02:00
Weblate
a87861a993 Merge remote-tracking branch 'origin/dev' into dev 2018-03-25 23:34:16 +02:00
AB
65476356c9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (354 of 354 strings)
2018-03-25 23:34:12 +02:00
Christian Schabesberger
8af6667f3e Merge pull request #1212 from karyogamy/sub-quick-fix
Subscription Front Page Crash Fix
2018-03-25 20:31:36 +02:00
John Zhen Mo
b546df7b95 -Fixed activity not available exception when setting title on subscription fragments when used as front pager. 2018-03-25 10:29:37 -07:00
Emanuele Petriglia
20c1f12da8 Translated using Weblate (Italian)
Currently translated at 100.0% (354 of 354 strings)
2018-03-25 13:21:40 +02:00
Weblate
e65ff201af Merge remote-tracking branch 'origin/dev' into dev 2018-03-25 11:36:18 +02:00
Tobias Groza
4f367a3dcd Translated using Weblate (German)
Currently translated at 89.8% (318 of 354 strings)
2018-03-25 11:36:16 +02:00
Heimen Stoffels
d7093bce4d Translated using Weblate (Dutch)
Currently translated at 100.0% (354 of 354 strings)
2018-03-25 11:36:13 +02:00
Christian Schabesberger
79e3e59cae move on to version 0.13.0 2018-03-25 11:18:51 +02:00
anonymous
f1b292df93 Translated using Weblate (German)
Currently translated at 89.8% (318 of 354 strings)
2018-03-25 00:41:30 +01:00
Tobias Groza
0cd383b8dd Translated using Weblate (German)
Currently translated at 88.9% (315 of 354 strings)
2018-03-25 00:40:01 +01:00
Weblate
22c404a667 Merge remote-tracking branch 'origin/dev' into dev 2018-03-24 18:40:13 +01:00
Oleh Ilnytskyi
ba11a59d89 Translated using Weblate (Polish)
Currently translated at 93.0% (319 of 343 strings)
2018-03-24 18:40:13 +01:00
Freddy Morán Jr
06020851a9 Translated using Weblate (Spanish)
Currently translated at 100.0% (343 of 343 strings)
2018-03-24 18:40:07 +01:00
Christian Schabesberger
fd5cbde18c fix readme conflict 2018-03-24 10:56:31 +01:00
Christian Schabesberger
384398a1e2 Merge branch 'qol-updates' of https://github.com/karyogamy/NewPipe into ui 2018-03-24 10:50:17 +01:00
Christian Schabesberger
2bdba4ba8b fix somehow broken librepay donate link 2018-03-24 10:35:43 +01:00
Christian Schabesberger
db4179a530 fix weird librepay link broken 2018-03-24 10:25:42 +01:00
Christian Schabesberger
b905b74dc2 Merge pull request #1201 from TobiGr/readme
Update README.md
2018-03-24 10:21:58 +01:00
Mohammad Hassan
ff05c36856 Translated using Weblate (Arabic)
Currently translated at 87.4% (300 of 343 strings)
2018-03-24 02:34:15 +01:00
TobiGr
40ea5eb53d Update README.md
Add compressed screenshots
Add liberapay to donation section
2018-03-23 16:15:50 +01:00
John Zhen Mo
02f48ccc7f -Removed duplicate dialog open instances in service player activity. 2018-03-22 18:44:03 -07:00
John Zhen Mo
72eaff148c -Fixed main player paused video not abandoning audio focus after navigating away from activity during interruption, when resume on focus regain is enabled.
-Separated onPause and onPlay functions from onPlayPause.
-Renamed onVideoPlayPause to onPlayPause.
2018-03-22 18:12:11 -07:00
John Zhen Mo
8b60397f06 -Changed detail fragment thumbnail failure to produce a snackbar error rather than a full error activity. 2018-03-22 18:11:59 -07:00
John Zhen Mo
18d019c62a -Added quadratic slider strategy implementation and tests.
-Modified playback speed control to use quadratic sliders instead of linear.
-Modified number formatters in player helper to use double instead of float.
-Simplified slider behavior in playback parameter dialog.
-Fixed potential NPE in base local fragment.
2018-03-21 20:08:33 -07:00
Weblate
27527b18e1 Merge remote-tracking branch 'origin/dev' into dev 2018-03-21 23:37:21 +01:00
Tobias Groza
ae9aa2662a Translated using Weblate (German)
Currently translated at 93.2% (320 of 343 strings)
2018-03-21 23:37:17 +01:00
Christian Schabesberger
3bfb593b21 Merge pull request #1197 from TeamNewPipe/remove-ip-range
Remove IP range
2018-03-21 20:59:41 +01:00
wb9688
8556e99241 Remove IP range
This would close #1148. I haven't tested it myself yet. @TheAssassin: Could you update the Sentry part?
2018-03-21 10:55:22 +01:00
John Zhen Mo
e885822a34 -Added playback speed control dialog to allow full user control over player tempo and pitch parameters.
-Changed tempo and pitch button in service player activity and tempo button in main video player to open speed control dialog.
-Changed LIVE button to be no longer clickable when player position is at or beyond default position.
-Changed main video player to use AppCompatActivity rather than Activity.
-Fixed video player tempo button not updating when player speed parameters change.
-Fixed player crashing on lower sdk versions due to no MediaButtonReceiver, added intent back to manifest.
-Fixed inconsistent gradle library naming.
-Fixed stetho dependencies incorrect version.
2018-03-21 00:11:54 -07:00
Weblate
8ebb564a79 Merge remote-tracking branch 'origin/dev' into dev 2018-03-20 16:36:52 +01:00
Tobias Groza
7dc176edcb Translated using Weblate (German)
Currently translated at 93.2% (320 of 343 strings)
2018-03-20 16:36:47 +01:00
John Zhen Mo
5167fe078b -Refactored synchronization checks out from MediaSourceManager to ManagedMediaSource.
-Fixed null input causing potential NPE on PlayQueueItem.
2018-03-19 16:44:18 -07:00
John Zhen Mo
bc7188c8a8 -Added media session implementation for all players.
-Extracted version numbers in gradle dependencies.
-Updated ExoPlayer to 2.7.1.
-Updated RxJava to 2.1.10, RxAndroid to 2.0.2 and RxBinding to 2.1.1.
-Removed deprecated implementation of media buttons.
2018-03-19 16:44:18 -07:00
John Zhen Mo
5a05cb96be -Changed start position seek to occur after media source window has been prepared.
-Fixed livestream not seeking to live when started from play queue.
-Fixed media source manager synchronization to only occur after timeline change has completed.
-Fixed auto queue not working when last item is replayed after the auto-queued item is removed.
-Updated ExoPlayer to 2.7.1.
2018-03-19 16:44:17 -07:00
John Zhen Mo
0258726f0a -Changed thumbnail toggle in disabled mode to load dark dummy image.
-Changed play queue items to display service names.
-Fixed Soundcloud playlist not fitting thumbnail.
-Refactored image display options to follow uniform behavior.
-Refactoring and style changes on audio reactor and media button receiver.
2018-03-19 16:44:17 -07:00
John Zhen Mo
2fa9aa04f4 -Bump support library and multidex version. 2018-03-19 16:40:40 -07:00
John Zhen Mo
a5f9927459 -Fixed main player animations not working on first call. 2018-03-19 16:40:40 -07:00
John Zhen Mo
61b422502b -[#1060] Added toggle to disable thumbnail loading.
-Added button to wipe metadata cache.
-Added more paddings on player buttons.
-Added new animations to main player secondary controls and play queue expand/collapse.
-Refactored play queue item touch callback for use in all players.
-Improved MediaSourceManager to better handle expired stream reloading.
-[#1186] Changed live sync button text to "LIVE".
-Removed MediaSourceManager loader coupling on main players.
-Moved service dependent expiry resolution to ServiceHelper.
-[#1186] Fixed livestream timeline updates causing negative time position.
-[#1186] Fixed livestream not starting from live-edge.
-Fixed main player system UI not retracting on playback start.
2018-03-19 16:40:40 -07:00
Christian Schabesberger
1e57b5ea49 Merge pull request #1193 from TeamNewPipe/fix_page
made frontend combatible to latest extractor refactorings
2018-03-19 23:22:28 +01:00
Allan Nordhøy
12ce915e8e Translated using Weblate (Norwegian Bokmål)
Currently translated at 93.2% (320 of 343 strings)
2018-03-19 22:44:34 +01:00
ezjerry liao
a32273af91 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (343 of 343 strings)
2018-03-19 12:40:50 +01:00
Christian Schabesberger
96a327af17 made frontend combatible to latest extractor refactorings 2018-03-18 16:37:49 +01:00
AB
1910e81ad9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (343 of 343 strings)
2018-03-18 14:40:32 +01:00
ezjerry liao
80593e774c Translated using Weblate (Chinese (Traditional))
Currently translated at 99.7% (342 of 343 strings)
2018-03-18 13:35:17 +01:00
AB
c092fc8e18 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (343 of 343 strings)
2018-03-17 13:40:27 +01:00
E T
579efa15c7 Translated using Weblate (Turkish)
Currently translated at 100.0% (343 of 343 strings)
2018-03-17 12:40:00 +01:00
E T
37ff4e9aeb Translated using Weblate (Turkish)
Currently translated at 100.0% (343 of 343 strings)
2018-03-16 12:21:00 +01:00
Weblate
4e4a7de5d4 Merge remote-tracking branch 'origin/dev' into dev 2018-03-15 15:35:15 +01:00
Olexandr Nesterenko
2d1bc6436a Translated using Weblate (Ukrainian)
Currently translated at 98.8% (339 of 343 strings)
2018-03-15 15:35:15 +01:00
Edwar Tikhonov
65726d75cc Translated using Weblate (Russian)
Currently translated at 100.0% (343 of 343 strings)
2018-03-15 15:35:13 +01:00
Yaron Shahrabani
d63c0a32eb Translated using Weblate (Hebrew)
Currently translated at 75.8% (260 of 343 strings)
2018-03-15 15:35:12 +01:00
ezjerry liao
e49c4162e5 Translated using Weblate (Chinese (Traditional))
Currently translated at 98.5% (338 of 343 strings)
2018-03-15 15:35:07 +01:00
Christian Schabesberger
ffc5ad5ce7 Merge branch 'media_buttons' of https://github.com/alexandrepa/NewPipe into media 2018-03-14 18:27:17 +01:00
Edwar Tikhonov
2dbfc28d69 Translated using Weblate (Russian)
Currently translated at 100.0% (343 of 343 strings)
2018-03-14 16:34:36 +01:00
ezjerry liao
1ac7b2b8cb Translated using Weblate (Chinese (Traditional))
Currently translated at 98.2% (337 of 343 strings)
2018-03-14 13:35:30 +01:00
cozyplanes
7d047e612e Translated using Weblate (Korean)
Currently translated at 100.0% (343 of 343 strings)
2018-03-14 12:38:22 +01:00
alexandre patelli
24f2999669 Handling play/pause button from different headsets 2018-03-13 22:57:59 +01:00
Eduardo Caron
b08728b645 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (339 of 343 strings)
2018-03-13 18:38:49 +01:00
cozyplanes
00dee43a1e Translated using Weblate (Korean)
Currently translated at 100.0% (343 of 343 strings)
2018-03-13 12:23:55 +01:00
Freddy Morán Jr
21e300b9f3 Translated using Weblate (Spanish)
Currently translated at 100.0% (343 of 343 strings)
2018-03-12 21:18:01 +01:00
Emanuele Petriglia
158f0aa2d9 Translated using Weblate (Italian)
Currently translated at 100.0% (343 of 343 strings)
2018-03-12 17:53:29 +01:00
Weblate
10fb763d66 Merge remote-tracking branch 'origin/dev' into dev 2018-03-12 17:00:19 +01:00
cozyplanes
4aa2c1c2c2 Translated using Weblate (Korean)
Currently translated at 95.0% (326 of 343 strings)
2018-03-12 17:00:18 +01:00
Heimen Stoffels
bdf044d264 Translated using Weblate (Dutch)
Currently translated at 100.0% (343 of 343 strings)
2018-03-12 17:00:08 +01:00
Christian Schabesberger
6049a1f2f5 fix playlist banner foo 2018-03-12 16:18:03 +01:00
Christian Schabesberger
a9fea9f606 fix release crash because of setting sidebar header 2018-03-12 16:00:38 +01:00
Weblate
11002e9d45 Merge remote-tracking branch 'origin/dev' into dev 2018-03-12 15:50:38 +01:00
cozyplanes
e7a0b850df Translated using Weblate (Korean)
Currently translated at 100.0% (324 of 324 strings)
2018-03-12 15:50:33 +01:00
Christian Schabesberger
736c902f3c fix weblate conflict 2018-03-11 21:38:19 +01:00
ButterflyOfFire
a67ff564d0 Translated using Weblate (Arabic)
Currently translated at 91.6% (297 of 324 strings)
2018-03-11 20:36:51 +01:00
Andreas Kleinert
2a778383b1 Translated using Weblate (German)
Currently translated at 93.2% (302 of 324 strings)
2018-03-11 20:36:47 +01:00
alexandre patelli
36457400e7 Review Fixes 2018-03-11 19:23:00 +01:00
alexandre patelli
1d629e7b2e Direct use of AudioManager from AudioReactor 2018-03-11 15:09:11 +01:00
alexandre patelli
5f764ab8f5 Media Button Play/Pause, Previous and Next in Background Player 2018-03-10 18:25:20 +01:00
Pablo Hinojosa
a8c9edbc3f Translated using Weblate (Spanish)
Currently translated at 100.0% (324 of 324 strings)
2018-03-10 17:38:49 +01:00
Emanuele Petriglia
0a5bffe826 Translated using Weblate (Italian)
Currently translated at 100.0% (324 of 324 strings)
2018-03-10 17:38:39 +01:00
Mauricio Colli
9c9b6bc0d6 Change thumbnail's scale strategy
- Closes #1054
2018-03-10 13:36:50 -03:00
Mauricio Colli
562f7e7e41 Add duration view to video detail fragment
- Add "textAllCaps" to the mini stream layout
- Closes #609
2018-03-10 13:20:10 -03:00
Mauricio Colli
594c55afa6 Merge pull request #1145 from mauriciocolli/dev
Implement subscriptions import/export
2018-03-10 12:11:13 -03:00
Pablo Hinojosa
0abf97e999 Translated using Weblate (Spanish)
Currently translated at 100.0% (324 of 324 strings)
2018-03-10 16:07:50 +01:00
Freddy Morán Jr
b811aec773 Translated using Weblate (Spanish)
Currently translated at 98.7% (320 of 324 strings)
2018-03-10 15:47:34 +01:00
AB
ca47f566dc Translated using Weblate (Ukrainian)
Currently translated at 100.0% (324 of 324 strings)
2018-03-10 14:41:06 +01:00
Yaron Shahrabani
65674f7fd4 Translated using Weblate (Hebrew)
Currently translated at 79.6% (258 of 324 strings)
2018-03-10 09:36:40 +01:00
Eduardo Caron
dcc510ff6c Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.7% (320 of 324 strings)
2018-03-10 00:39:26 +01:00
Emanuele Petriglia
a4fe43a964 Translated using Weblate (Italian)
Currently translated at 100.0% (324 of 324 strings)
2018-03-09 16:44:18 +01:00
Kotoba Murasaki
3dab4c07cf Translated using Weblate (Ukrainian)
Currently translated at 100.0% (324 of 324 strings)
2018-03-09 13:52:18 +01:00
E T
ee3248ea5d Translated using Weblate (Turkish)
Currently translated at 100.0% (324 of 324 strings)
2018-03-09 12:28:47 +01:00
anonymous
7be5ec0521 Translated using Weblate (Hebrew)
Currently translated at 79.3% (257 of 324 strings)
2018-03-09 09:25:05 +01:00
Yaron Shahrabani
04e90cc279 Translated using Weblate (Hebrew)
Currently translated at 78.7% (255 of 324 strings)
2018-03-09 09:24:48 +01:00
anonymous
ec8d488249 Translated using Weblate (Hebrew)
Currently translated at 78.0% (253 of 324 strings)
2018-03-09 09:24:03 +01:00
Yaron Shahrabani
41fdafac45 Translated using Weblate (Hebrew)
Currently translated at 76.8% (249 of 324 strings)
2018-03-09 09:23:19 +01:00
anonymous
d2e2622279 Translated using Weblate (Hebrew)
Currently translated at 75.9% (246 of 324 strings)
2018-03-09 09:22:41 +01:00
Yaron Shahrabani
9476bd6527 Translated using Weblate (Hebrew)
Currently translated at 75.6% (245 of 324 strings)
2018-03-09 09:22:32 +01:00
anonymous
24a06ea6f6 Translated using Weblate (Hebrew)
Currently translated at 75.6% (245 of 324 strings)
2018-03-09 09:22:09 +01:00
Yaron Shahrabani
2567f8eefb Translated using Weblate (Hebrew)
Currently translated at 75.3% (244 of 324 strings)
2018-03-09 09:21:54 +01:00
ezjerry liao
fa5f5ce251 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (324 of 324 strings)
2018-03-09 02:58:02 +01:00
Heimen Stoffels
728a61756a Translated using Weblate (Dutch)
Currently translated at 100.0% (324 of 324 strings)
2018-03-08 21:25:11 +01:00
Kotoba Murasaki
736ccbe376 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (324 of 324 strings)
2018-03-08 20:38:45 +01:00
Weblate
fa2b226b9e Merge remote-tracking branch 'origin/dev' into dev 2018-03-08 20:24:24 +01:00
Kotoba Murasaki
e8c5ae194d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (318 of 318 strings)
2018-03-08 20:24:19 +01:00
Mauricio Colli
cc2feab37e Implement UI for subscriptions import/export
- Nice and easy to use import/export options in the subscriptions fragment
- Includes instructions for each service (in the import fragment/screen)
2018-03-08 11:50:46 -03:00
Mauricio Colli
83b084a90b Implement subscriptions import/export
- Import subscriptions from YouTube and SoundCloud (all services that the extractor support)
- Import/export a JSON representation of the subscriptions
- [Minor] Remove some javax annotations in favor of the one provided by the android support library
2018-03-08 10:39:24 -03:00
Christian Schabesberger
e2ac0722c8 Merge pull request #1155 from TeamNewPipe/update-readme
Update README.md
2018-03-06 19:46:55 +01:00
Schabi
c3efb40b8e move to latest version of extractor 2018-03-06 19:44:17 +01:00
Schabi
03d7a416f3 add live lable to toolbar 2018-03-06 19:24:58 +01:00
Schabi
e6e812fdb0 Merge branch 'exoplayer-update' of https://github.com/karyogamy/NewPipe into live 2018-03-06 17:23:37 +01:00
John Zhen Mo
b34160eeec -Fixed main video player losing state when killed in background.
-Disabled auto queuing when repeating is enabled.
-Added method to use startForegroundService instead of startService in sdk 26 and up.
2018-03-05 19:03:49 -08:00
John Zhen Mo
d01aeab242 -Added auto-queuing to allow next or related streams to queue up when the last item on play queue is playing.
-Added toggle to enable auto-queuing.
-Modified main video player to only pause the video onPause.
-Fixed main video player not saving play queue state onStop.
2018-03-04 20:16:38 -08:00
anonymous
9904e01252 Translated using Weblate (Serbian)
Currently translated at 78.6% (250 of 318 strings)
2018-03-04 14:41:36 +01:00
John Zhen Mo
7f068b691b -Removed system ui on main player for Kitkat or above.
-[#1151] Hide video player UI on playing to avoid unnecessary interruptions after pause, seek and resize.
2018-03-03 20:58:53 -08:00
John Zhen Mo
59558efed1 -Added seamless shuffling.
-Reenabled full window loading in MediaSourceManager.
2018-03-03 20:58:06 -08:00
John Zhen Mo
a88e19a8ed -Added toggle to enable fast inexact seek in players.
-Improved player sync calls to recognize different metadata updates.
-Changed MediaSourceManager to synchronize only after timeline changes and reenabled multiple sync calls to player.
-Renamed listener and synchronization methods related to MediaSourceManager.
2018-03-03 14:24:21 -08:00
John Zhen Mo
0c17f0825b -Added loader eviction to avoid spawning too many threads in MediaSourceManager.
-Added nonnull and final constraints to variables in MediaSourceManager.
-Added nonnull and final constraints on context related objects in BasePlayer.
-Fixed Hls livestreams crashing player when behind live window for too long.
-Fixed cache miss when InfoCache key mismatch between StreamInfo and StreamInfoItem.
2018-03-03 11:42:23 -08:00
Mladen Pejaković
9384d2523a Translated using Weblate (Serbian)
Currently translated at 78.3% (249 of 318 strings)
2018-03-03 14:03:02 +01:00
anonymous
0e13172a89 Translated using Weblate (Serbian)
Currently translated at 78.3% (249 of 318 strings)
2018-03-03 14:02:34 +01:00
Mladen Pejaković
92f34452b5 Translated using Weblate (Serbian)
Currently translated at 77.9% (248 of 318 strings)
2018-03-03 14:02:17 +01:00
anonymous
db54929584 Translated using Weblate (Serbian)
Currently translated at 77.9% (248 of 318 strings)
2018-03-03 14:01:59 +01:00
Mladen Pejaković
ba23cafb18 Translated using Weblate (Serbian)
Currently translated at 77.6% (247 of 318 strings)
2018-03-03 14:01:43 +01:00
anonymous
a2e189767b Translated using Weblate (Serbian)
Currently translated at 77.3% (246 of 318 strings)
2018-03-03 14:01:30 +01:00
anonymous
0d236fd678 Translated using Weblate (Serbian)
Currently translated at 76.4% (243 of 318 strings)
2018-03-03 14:00:48 +01:00
Mladen Pejaković
9979b160c7 Translated using Weblate (Serbian)
Currently translated at 76.1% (242 of 318 strings)
2018-03-03 14:00:39 +01:00
anonymous
65b332c395 Translated using Weblate (Serbian)
Currently translated at 76.1% (242 of 318 strings)
2018-03-03 13:59:43 +01:00
Mladen Pejaković
b867ac8cc7 Translated using Weblate (Serbian)
Currently translated at 75.7% (241 of 318 strings)
2018-03-03 13:59:38 +01:00
Enol P
9a0ff24ffe Translated using Weblate (Asturian)
Currently translated at 97.4% (310 of 318 strings)
2018-03-03 03:34:28 +01:00
Eduardo Caron
9540a12b6f Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.0% (315 of 318 strings)
2018-03-03 01:41:17 +01:00
wb9688
fdfb53c05c Update README.md 2018-03-02 10:10:15 +01:00
HardLight
3ec979cc40 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (318 of 318 strings)
2018-03-01 22:38:41 +01:00
John Zhen Mo
9ea08c8a4b -Re-added loading for items prior to current index in MediaSourceManager to allow faster access time.
-Added some null checks annotation.
2018-02-28 23:25:45 -08:00
Digiwizkid
629eada5c3 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 40.5% (129 of 318 strings)
2018-03-01 04:34:43 +01:00
John Zhen Mo
a1220c77da -Added serialized cache for transferring serializable objects too large for intent transactions.
-Fixed potential transaction too large exceptions for player intents.
2018-02-28 17:47:12 -08:00
John Zhen Mo
b4668367c6 -Added better assertions and documentations to new mechanism in MediaSourceManager.
-Modified LoadController to allow fast playback start and increased buffer zigzag window.
-Removed unnecessary loading on timeline changes.
-Changed select message in MediaSourceManager to cause immediate load.
-Reduced default expiration time in MediaSourceManager.
-Fixed main video player not showing end time on audio-only streams.
-Fixed live stream has player view disabled after transitioning from audio stream.
-Fixed inconsistent progress bar height between live and non-live video on main player.
2018-02-28 17:45:05 -08:00
John Zhen Mo
77da40e507 -Added perpetual extractor source loading on network failures.
-Fixed play queue playlist desynchronization caused by media source manager window loading expansion on sublist prior to current item.
-Fixed failed media source not treated as ready for playback.
2018-02-26 22:37:19 -08:00
John Zhen Mo
b3b2748bb7 -Improved player queue stability by using more aggressive synchronization policy.
-Added sync buttons on live streams to allow seeking to live edge.
-Added custom cache key for extractor sources to allow more persistent reuse.
-Refactored player data source factories into own class and separating live and non-live data sources.
2018-02-26 19:57:59 -08:00
ezjerry liao
26e8143616 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (318 of 318 strings)
2018-02-26 14:30:19 +01:00
John Zhen Mo
1444fe5468 -Fixed potential NPE when obtaining broadcast receiver.
-Extracted expiration time in media source manager.
-Re-enabled long click on live stream info items.
-Fixed dash source building to use mpd instead of extractor.
2018-02-25 20:12:30 -08:00
John Zhen Mo
ac431e3ece -Fixed failed media source not treated as ready. 2018-02-25 15:32:25 -08:00
John Zhen Mo
563a4137bd -Fixed inconsistent audio focus state when audio becomes noisy (e.g. headset unplugged).
-Fixed live media sources failing when using cached data source by introducing
cacheless data sources.
-Added custom track selector to circumvent ExoPlayer's language normalization NPE.
-Updated Extractor to correctly load live streams.
-Removed deprecated deferred media source and media source manager.
-Removed Livestream exceptions.
2018-02-25 15:10:11 -08:00
John Zhen Mo
19cbcd0c1d -Fixed media source update index check.
-Fixed media source manager excessive loading.
-Remove unneeded fields in loaded media source.
2018-02-24 21:54:47 -08:00
John Zhen Mo
8803b60b28 -Updated Exoplayer to 2.7.0.
-PoC for new seamless stream loading mechanism.
2018-02-24 21:54:47 -08:00
Weblate
e9f59ae769 Merge remote-tracking branch 'origin/dev' into dev 2018-02-24 23:37:04 +01:00
Matej U
5cf3bee336 Translated using Weblate (Slovenian)
Currently translated at 77.3% (246 of 318 strings)
2018-02-24 23:37:04 +01:00
Maciej Gamrat
060fe835c7 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 23:37:02 +01:00
Toldi Balázs
2688ea8f59 Translated using Weblate (Hungarian)
Currently translated at 44.6% (142 of 318 strings)
2018-02-24 23:37:01 +01:00
Arun Negi
8eb61cf752 Translated using Weblate (Hindi)
Currently translated at 99.6% (317 of 318 strings)
2018-02-24 23:36:56 +01:00
Tobias Groza
6628901d46 Translated using Weblate (German)
Currently translated at 94.6% (301 of 318 strings)
2018-02-24 23:36:52 +01:00
Christian Schabesberger
5a31882be3 Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2018-02-24 22:57:34 +01:00
Christian Schabesberger
a42da09d6c make NewPipe compatible with latest Extractor refactorings 2018-02-24 22:57:25 +01:00
nieko-nera
658cf5c873 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 19:38:45 +01:00
Coffeemaker
b8c752b740 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 18:51:39 +01:00
Maciej Gamrat
9151ae7081 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 18:51:28 +01:00
anonymous
a1a894f722 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 18:50:22 +01:00
Maciej Gamrat
3352ee3151 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 18:49:38 +01:00
Maciej Gamrat
da3533a430 Translated using Weblate (Polish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 18:48:41 +01:00
anonymous
0bb7f9becf Translated using Weblate (Polish)
Currently translated at 83.0% (264 of 318 strings)
2018-02-24 18:02:21 +01:00
Maciej Gamrat
40c64ee2d8 Translated using Weblate (Polish)
Currently translated at 83.0% (264 of 318 strings)
2018-02-24 18:01:21 +01:00
r2308145
66651f7111 Translated using Weblate (Czech)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 13:43:02 +01:00
Freddy Morán Jr
c7d0bd5dec Translated using Weblate (Spanish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-24 03:40:58 +01:00
anonymous
9ce0a9d49d Translated using Weblate (Hungarian)
Currently translated at 30.5% (97 of 318 strings)
2018-02-23 22:54:03 +01:00
Toldi Balázs
2070b353c2 Translated using Weblate (Hungarian)
Currently translated at 30.1% (96 of 318 strings)
2018-02-23 22:52:47 +01:00
anonymous
1d91f3b91b Translated using Weblate (Hungarian)
Currently translated at 29.5% (94 of 318 strings)
2018-02-23 22:52:04 +01:00
Toldi Balázs
8b0aebfddb Translated using Weblate (Hungarian)
Currently translated at 29.2% (93 of 318 strings)
2018-02-23 22:51:13 +01:00
anonymous
467905d7b0 Translated using Weblate (Hungarian)
Currently translated at 29.2% (93 of 318 strings)
2018-02-23 22:50:48 +01:00
Toldi Balázs
cc81921bcb Translated using Weblate (Hungarian)
Currently translated at 28.9% (92 of 318 strings)
2018-02-23 22:50:36 +01:00
anonymous
8600c04ff3 Translated using Weblate (Hungarian)
Currently translated at 28.6% (91 of 318 strings)
2018-02-23 22:50:00 +01:00
Toldi Balázs
3f31445f12 Translated using Weblate (Hungarian)
Currently translated at 27.3% (87 of 318 strings)
2018-02-23 22:49:15 +01:00
anonymous
8a33371f37 Translated using Weblate (Hungarian)
Currently translated at 26.7% (85 of 318 strings)
2018-02-23 22:48:01 +01:00
Toldi Balázs
1164bd7183 Translated using Weblate (Hungarian)
Currently translated at 25.7% (82 of 318 strings)
2018-02-23 22:40:53 +01:00
anonymous
589fcd09c0 Translated using Weblate (Hungarian)
Currently translated at 25.4% (81 of 318 strings)
2018-02-23 22:40:37 +01:00
Weblate
c5d49016d4 Merge remote-tracking branch 'origin/dev' into dev 2018-02-23 18:48:55 +01:00
Freddy Morán Jr
8886b12151 Translated using Weblate (Spanish)
Currently translated at 99.0% (315 of 318 strings)
2018-02-23 18:48:54 +01:00
nieko-nera
336ffd7cf0 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (318 of 318 strings)
2018-02-23 18:48:50 +01:00
Christian Schabesberger
3088778a9f Merge pull request #1136 from wb9688/okhttp-uil
Use OkHttp with UIL
2018-02-23 18:06:13 +01:00
E T
4c1de83b24 Translated using Weblate (Turkish)
Currently translated at 100.0% (318 of 318 strings)
2018-02-23 11:43:24 +01:00
Emanuele Petriglia
ee2fbfc2d1 Translated using Weblate (Italian)
Currently translated at 100.0% (318 of 318 strings)
2018-02-23 09:46:40 +01:00
Heimen Stoffels
dff7fe722b Translated using Weblate (Dutch)
Currently translated at 100.0% (318 of 318 strings)
2018-02-22 22:48:45 +01:00
Weblate
eb6dac2e9f Merge remote-tracking branch 'origin/dev' into dev 2018-02-22 22:41:15 +01:00
Oleh Ilnytskyi
255760de16 Translated using Weblate (Ukrainian)
Currently translated at 69.8% (220 of 315 strings)
2018-02-22 22:41:09 +01:00
wb9688
a2373b817a Use OkHttp with UIL 2018-02-22 13:25:56 +01:00
Christian Schabesberger
72a9940863 Merge branch 'player_fix' of https://github.com/karyogamy/NewPipe into dev 2018-02-21 23:20:08 +01:00
Christian Schabesberger
46e088b5f3 made debug setting get a debug symbol 2018-02-21 23:14:14 +01:00
Christian Schabesberger
a3468b51e2 Merge branch 'pfix' into dev 2018-02-21 23:00:56 +01:00
John Zhen Mo
34f19c4268 -Changed Rx exception handling to swallow undeliverable exceptions by default. 2018-02-21 10:42:54 -08:00
Mauricio Colli
1d2c616ce0 Improve some aspects of the Downloader implementation 2018-02-21 08:08:52 -03:00
r2308145
99e0f0c3e4 Translated using Weblate (Czech)
Currently translated at 100.0% (315 of 315 strings)
2018-02-21 12:04:15 +01:00
Christian Schabesberger
7d4c45c4c0 Merge tag 'v0.11.6-beta'
v0.11.6-beta
2018-02-21 11:38:48 +01:00
John Zhen Mo
1a92dfb019 -Changed global Rx exception handling to no longer trigger error activity if the exception is undeliverable.
-Added debug settings to force reporting of undeliverable Rx exceptions.
-Changed back MediaSourceManager to use serial disposable for syncing.
2018-02-20 22:35:34 -08:00
John Zhen Mo
cc7f27fb53 -Added debug default values on settings init. 2018-02-20 21:16:53 -08:00
John Zhen Mo
e8402008bc -Added debug preference settings for debug and beta builds.
-Removed leak canary toggle on app menu.
-Added leak canary settings to debug preference.
-Removed/renamed leak canary related strings.
2018-02-20 21:16:53 -08:00
John Zhen Mo
c1a302834c -Fixed auto-generated string not translatable. 2018-02-20 21:15:23 -08:00
John Zhen Mo
762f374f93 -Fixed media source manager sync identical item multiple times, causing OOM.
-Removed deprecated translated leak canary string from other languages.
2018-02-20 21:15:23 -08:00
John Zhen Mo
e21d2bd511 -Fixed video player source loading for audio only streams.
-Changed "monitor leak" string to "LeakCanary" as untranslatable.
2018-02-20 21:15:23 -08:00
John Zhen Mo
d936ca6b89 -Added view registration on repeats.
-Added drag reorder speed clamping to play queue list.
-Fixed service player activity memory leak.
-Fixed media source manager sync disposable fallthrough causing NPE.
-Fixed thread bouncing during play queue item async stream resolution.
-Updated ExoPlayer to 2.6.0.
2018-02-20 21:15:23 -08:00
Weblate
88ac821070 Merge remote-tracking branch 'origin/dev' into dev 2018-02-21 02:52:10 +01:00
Arun Negi
c20837d5f5 Translated using Weblate (Hindi)
Currently translated at 100.0% (315 of 315 strings)
2018-02-21 02:52:09 +01:00
aladar42
81a4c66f92 Translated using Weblate (Czech)
Currently translated at 98.7% (311 of 315 strings)
2018-02-21 02:52:07 +01:00
ezjerry liao
e4dfb02cb0 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (315 of 315 strings)
2018-02-21 02:52:03 +01:00
Christian Schabesberger
0abaab4880 Merge branch 'okhttp' of https://github.com/wb9688/NewPipe into ht 2018-02-21 00:28:03 +01:00
Christian Schabesberger
a1aaa52c2a add link to NewPipe blog 2018-02-21 00:24:43 +01:00
Emanuele Petriglia
b3a509ad14 Translated using Weblate (Italian)
Currently translated at 100.0% (315 of 315 strings)
2018-02-20 19:12:39 +01:00
Freddy Morán Jr
ad0f58090f Translated using Weblate (Spanish)
Currently translated at 100.0% (315 of 315 strings)
2018-02-20 18:48:54 +01:00
Heimen Stoffels
43c4e619c2 Translated using Weblate (Dutch)
Currently translated at 100.0% (315 of 315 strings)
2018-02-20 17:52:58 +01:00
wb9688
427397ba7b Translated using Weblate (Dutch)
Currently translated at 99.6% (314 of 315 strings)
2018-02-20 17:52:53 +01:00
Arun Negi
b51abf1ea6 Translated using Weblate (Hindi)
Currently translated at 100.0% (315 of 315 strings)
2018-02-20 16:39:48 +01:00
wb9688
76e082159d Use OkHttp 2018-02-20 16:24:43 +01:00
Weblate
d36c371c1d Merge remote-tracking branch 'origin/dev' into dev 2018-02-20 14:36:49 +01:00
Marian Hanzel
a5b2100f8a Translated using Weblate (Slovak)
Currently translated at 100.0% (314 of 314 strings)
2018-02-20 14:36:49 +01:00
S Pimenta
fe19780f06 Translated using Weblate (Portuguese)
Currently translated at 80.2% (252 of 314 strings)
2018-02-20 14:36:48 +01:00
justanidea
83f1d7af82 Translated using Weblate (French)
Currently translated at 96.4% (303 of 314 strings)
2018-02-20 14:36:48 +01:00
ezjerry liao
1916616b07 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.0% (311 of 314 strings)
2018-02-20 14:36:47 +01:00
anonymous
0a6a684acc Translated using Weblate (Hindi)
Currently translated at 76.1% (239 of 314 strings)
2018-02-20 14:36:43 +01:00
Christian Schabesberger
6d9aecd500 update extractor 2018-02-20 13:52:20 +01:00
Christian Schabesberger
4d25db2e11 move on to version 0.12.0 2018-02-20 13:44:32 +01:00
Christian Schabesberger
77d5714059 Merge pull request #1109 from TobiGr/soundcloud-kiosk
Enable SoundCloud kiosks as main page fragment for debug and beta
2018-02-20 13:38:20 +01:00
Christian Schabesberger
76c59cbdea Merge pull request #1125 from TeamNewPipe/header
Header
2018-02-19 22:42:02 +01:00
Christian Schabesberger
212f7dfc93 fix drawer header service label noch chaning, and other things 2018-02-19 21:04:13 +01:00
CookieCaptain D
9ba37ce34c Translated using Weblate (Portuguese)
Currently translated at 77.7% (244 of 314 strings)
2018-02-19 20:05:18 +01:00
S Pimenta
6c439bfbc4 Translated using Weblate (Portuguese)
Currently translated at 77.3% (243 of 314 strings)
2018-02-19 20:04:30 +01:00
CookieCaptain D
352d0db08b Translated using Weblate (Portuguese)
Currently translated at 76.4% (240 of 314 strings)
2018-02-19 20:03:22 +01:00
S Pimenta
be8ce1fce5 Translated using Weblate (Portuguese)
Currently translated at 75.7% (238 of 314 strings)
2018-02-19 20:02:28 +01:00
Marian Hanzel
f6356e576a Translated using Weblate (Slovak)
Currently translated at 100.0% (314 of 314 strings)
2018-02-19 17:48:30 +01:00
Florian
83a34a8ba1 Translated using Weblate (French)
Currently translated at 89.4% (281 of 314 strings)
2018-02-19 12:36:11 +01:00
Freddy Morán Jr
fb7a855eda Translated using Weblate (Spanish)
Currently translated at 96.8% (304 of 314 strings)
2018-02-18 19:38:56 +01:00
Weblate
9c1d778623 Merge remote-tracking branch 'origin/dev' into dev 2018-02-17 15:51:54 +01:00
Eduardo Caron
1bad2a023d Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.3% (312 of 314 strings)
2018-02-17 15:51:53 +01:00
Allan Nordhøy
999da51e99 Translated using Weblate (Norwegian Bokmål)
Currently translated at 97.4% (306 of 314 strings)
2018-02-17 15:51:52 +01:00
Tobias Groza
ea4b965eeb Translated using Weblate (German)
Currently translated at 94.5% (297 of 314 strings)
2018-02-17 15:51:51 +01:00
E T
33160e83cb Translated using Weblate (Turkish)
Currently translated at 100.0% (314 of 314 strings)
2018-02-17 15:51:48 +01:00
Christian Schabesberger
3e5e7f49cc add inital drawer hader layout 2018-02-16 23:56:04 +01:00
Christian Schabesberger
cc02b01c2b Merge pull request #1111 from TeamNewPipe/renav
add header/footer to drawer
2018-02-16 21:43:39 +01:00
Christian Schabesberger
243e5391db Merge pull request #1106 from TeamNewPipe/upenuns
Remove actionBarHandler
2018-02-16 21:42:54 +01:00
Nathan Follens
230ad5c04f Translated using Weblate (Dutch)
Currently translated at 100.0% (314 of 314 strings)
2018-02-16 21:23:48 +01:00
Emanuele Petriglia
289cfaa407 Translated using Weblate (Italian)
Currently translated at 100.0% (314 of 314 strings)
2018-02-16 19:12:05 +01:00
Weblate
0798745c16 Merge remote-tracking branch 'origin/dev' into dev 2018-02-16 18:39:33 +01:00
Matej U
094695a7ff Translated using Weblate (Slovenian)
Currently translated at 81.8% (226 of 276 strings)
2018-02-16 18:39:27 +01:00
Christian Schabesberger
86f041b803 add header/footer to drawer 2018-02-16 14:45:52 +01:00
TobiGr
00e65153f4 Enable SoundCloud kiosks as main page fragment for debug and beta 2018-02-16 13:13:40 +01:00
Christian Schabesberger
b12f0490f3 remove ActionBarHandler 2018-02-16 12:18:15 +01:00
Christian Schabesberger
42a2bc8a9a clean DetailFragment code 2018-02-16 11:31:25 +01:00
Christian Schabesberger
8adca3725d solve merge conflict 2018-02-14 21:06:20 +01:00
Christian Schabesberger
b57d4b3048 Merge branch 'subtitles' of https://github.com/karyogamy/NewPipe into sub 2018-02-14 20:59:40 +01:00
Christian Schabesberger
9c7aa241e4 fixed preferred_player inconsistancy 2018-02-14 19:33:43 +01:00
Christian Schabesberger
c3ec9b2ad7 Merge pull request #1097 from TeamNewPipe/router
merge RouterActivity and RouterVideoActivity and add Hooktube support
2018-02-13 19:10:48 +01:00
Christian Schabesberger
195070f8f5 Merge branch 'dev' into router 2018-02-13 19:10:35 +01:00
Christian Schabesberger
cbfe91f36f merge RouterActivity and RouterVideoActivity
change share title

fixed compatiblity issue

rename info_screen to show_info
2018-02-12 23:07:17 +01:00
Christian Schabesberger
738e2ac344 merge RouterActivity and RouterVideoActivity 2018-02-12 19:44:35 +01:00
Christian Schabesberger
ba0be665ae fixed issues from prevoius merge 2018-02-12 00:43:12 +01:00
Christian Schabesberger
0ba6f8b39f Merge pull request #1092 from TeamNewPipe/icon
move download menu item into detail controls menu
2018-02-11 21:47:43 +01:00
Christian Schabesberger
2773f5fbc8 move download menu item into detail controls menu 2018-02-11 21:34:32 +01:00
John Zhen Mo
263a816c3b -Fixed preferences fetching. 2018-02-11 11:40:08 -08:00
John Zhen Mo
e7d148336b -Changed leak canary toggle text to "monitor leaks".
-Added toast when enabling/disabling heap dumping.
2018-02-11 11:33:17 -08:00
John Zhen Mo
829059ea01 -Added toggle for enabling leak canary heap dump. 2018-02-11 11:33:16 -08:00
John Zhen Mo
622d698ff8 -Added LeakCanary to debug build for memory detection on activities and fragments.
-Added LeakCanary no-op lib to release and beta builds.
2018-02-11 11:32:57 -08:00
John Zhen Mo
f09b04dce0 -Code clean up on resize switching. 2018-02-11 11:32:40 -08:00
John Zhen Mo
59f8583895 -Added settings for managing caption font size. 2018-02-11 11:32:40 -08:00
John Zhen Mo
f506fc0478 -Moved caption extraction and menu building into exoplayer track changing callback.
-Updated extractor dependency.
2018-02-11 11:32:39 -08:00
John Zhen Mo
880676d670 -Modified popup video player to show extra options only when screen is large enough.
-Modified available resize options for different player modes.
-Fixed caption menu not working on popup player.
-Extracted hardcoded strings.
-Added button effects to both main and popup players.
2018-02-11 11:32:39 -08:00
John Zhen Mo
6485327b97 -Replace main player dropdown menu with expand/collapse custom UI. 2018-02-11 11:32:10 -08:00
John Zhen Mo
5773152ed3 -Added subtitles loading and display.
-Added subtitles switching button to popup and main players.
-Added aspect ratio switching button to popup pand main players.
2018-02-11 11:31:49 -08:00
Christian Schabesberger
e88312659b Merge branch 'play' into dev 2018-02-11 20:26:06 +01:00
Christian Schabesberger
c4d0ba549f Merge pull request #1083 from comradekingu/patch-5
Spelling: ZIP, Warning:
2018-02-11 18:06:55 +01:00
John Zhen Mo
cb41afb11f -Fixed Soundcloud playlist bookmark button not working when entered from search page.
-Fixed NPE when playlist fragment is destroyed while renaming.
-Fixed remote playlist thumbnail to use uploader avatar when thumbnail url is unavailable.
-Added dispose on exit to all database requests in local playlist fragment.
2018-02-10 17:20:56 -08:00
Enol P
6d27aea9f2 Translated using Weblate (Asturian)
Currently translated at 100.0% (276 of 276 strings)
2018-02-10 16:43:12 +01:00
Eduardo Caron
39e1f9cb76 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.2% (274 of 276 strings)
2018-02-10 15:39:03 +01:00
M1ck
8fb7d64f79 Translated using Weblate (French)
Currently translated at 100.0% (276 of 276 strings)
2018-02-10 15:36:20 +01:00
E T
08fdef4870 Translated using Weblate (Turkish)
Currently translated at 100.0% (276 of 276 strings)
2018-02-09 17:32:51 +01:00
anonymous
aa0196b9d0 Translated using Weblate (French)
Currently translated at 100.0% (276 of 276 strings)
2018-02-09 14:38:10 +01:00
M1ck
a3426f92ac Translated using Weblate (French)
Currently translated at 99.6% (275 of 276 strings)
2018-02-09 14:38:05 +01:00
anonymous
d50d4254c5 Translated using Weblate (French)
Currently translated at 98.9% (273 of 276 strings)
2018-02-09 14:33:33 +01:00
M1ck
50cdadc4a2 Translated using Weblate (French)
Currently translated at 98.5% (272 of 276 strings)
2018-02-09 14:33:19 +01:00
anonymous
5aa9b6cb12 Translated using Weblate (French)
Currently translated at 98.5% (272 of 276 strings)
2018-02-09 14:33:00 +01:00
M1ck
44fc8d80e0 Translated using Weblate (French)
Currently translated at 97.4% (269 of 276 strings)
2018-02-09 14:31:44 +01:00
anonymous
817fa57bfe Translated using Weblate (French)
Currently translated at 97.4% (269 of 276 strings)
2018-02-09 14:30:52 +01:00
M1ck
668e2da01b Translated using Weblate (French)
Currently translated at 97.1% (268 of 276 strings)
2018-02-09 14:30:40 +01:00
anonymous
7f3982d153 Translated using Weblate (French)
Currently translated at 97.1% (268 of 276 strings)
2018-02-09 14:30:25 +01:00
John Zhen Mo
f62ae930c7 -Merged bookmark buttons on playlist fragment into one.
-Fixed bookmark button flickering on visibility toggling.
-Removed toolbar up button control from local fragments, delegating functionality back to main fragment.
-Updated extractor to latest.
2018-02-08 19:53:11 -08:00
John Zhen Mo
d0808ce159 -Fixed playlist creation icon in playlist append dialog.
-Fixed bookmarking disposable not part of playlist fragment lifecycle.
-Rearranged local fragment directory structure.
2018-02-08 18:48:36 -08:00
ezjerry liao
7b19dadbf5 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (276 of 276 strings)
2018-02-09 03:10:03 +01:00
Allan Nordhøy
43ab0283d9 ZIP, Warning: 2018-02-09 02:53:59 +01:00
Weblate
c27e9d5901 Merge remote-tracking branch 'origin/dev' into dev 2018-02-09 02:51:17 +01:00
ScratchBuild
e0d21627bb Translated using Weblate (Japanese)
Currently translated at 85.5% (236 of 276 strings)
2018-02-09 02:51:15 +01:00
ezjerry liao
1b1dd6ef88 Translated using Weblate (Chinese (Traditional))
Currently translated at 96.0% (265 of 276 strings)
2018-02-09 02:51:11 +01:00
Allan Nordhøy
10700007d5 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (276 of 276 strings)
2018-02-09 02:51:08 +01:00
John Zhen Mo
c5ec8d04c1 -Fixed playlist bookmark button not showing out when activity / playlist fragment is created by external share. 2018-02-08 15:58:48 -08:00
John Zhen Mo
490b250db6 -Removed Leak Canary dependency.
-Fixed local playlist header margins.
2018-02-08 11:53:08 -08:00
John Zhen Mo
0630423c8e -Fixed bookmark fragment in main pager not showing hamburger menu. 2018-02-08 10:13:29 -08:00
Christian Schabesberger
c2e06517e1 Merge pull request #1074 from TeamNewPipe/fix-sc
Fix opening SoundCloud links
2018-02-08 12:51:15 +01:00
Rintaro matsuo
b01ae33d1e Translated using Weblate (Japanese)
Currently translated at 78.9% (218 of 276 strings)
2018-02-08 08:17:32 +01:00
ScratchBuild
a55ee32058 Translated using Weblate (Japanese)
Currently translated at 78.9% (218 of 276 strings)
2018-02-08 08:12:40 +01:00
John Zhen Mo
c3941d5bec -Added remote playlist table creation to migrations. 2018-02-07 19:24:36 -08:00
John Zhen Mo
6020dc2b2d -Renamed "watch history" fragment under bookmark to "last played".
-Renamed "watched history" fragment under history to "watch history".
2018-02-07 19:24:36 -08:00
John Zhen Mo
7ab41e0c3a -Added listener unregistration to local item adapters to release dependency and avoid memory leak.
-Added listener unregistration on all listeners using contexts in local item related fragments.
2018-02-07 19:24:36 -08:00
John Zhen Mo
c0a75f5b98 -Added ability to save playlist as remote playlist link rather than storing it in database.
-Added LeakCanary as part of debug build.
-Modified bookmark list to show both remote and local playlists.
-Removed ability to save channel items as local playlist, in favor of subscribe.
2018-02-07 19:24:36 -08:00
John Zhen Mo
efd4db40ef -Fixed NPE issues when button views are clicked on local playlist and statistics playlist fragments are out of focus.
-Added disk cache size limit for image loader.
-Fixed button names for playlist rename dialog.
2018-02-07 19:24:36 -08:00
John Zhen Mo
3c3fe7bf83 -Fixed database updates cause outdated record to overwrite reordered local playlist when fragment is active.
-Fixed save on exit causes empty list being saved after orientation changes on older devices.
-Fixed NPE on animating garbage collected views on local item fragments.
-Reduced drag speed from 15 to 12 items per second.
2018-02-07 19:24:36 -08:00
John Zhen Mo
268762166a -Added save on exit to local playlist fragment.
-Improved drag reordering experience by setting minimum velocity.
-Increased save debounce to 10 seconds.
2018-02-07 19:24:36 -08:00
John Zhen Mo
53a1833e26 -Increased save join debounce time to 2 seconds.
-Added add to playlist option for videos available as base list items.
-Moved video count to second row on local playlist header.
-Removed bottom line on playlist control UI.
2018-02-07 19:24:36 -08:00
John Zhen Mo
1ff8b5fb9f -Refactored info item and local item click gestures into the same OnClickGesture. 2018-02-07 19:24:35 -08:00
John Zhen Mo
225b43ca3c -Modified BaseLocalItemFragment to no longer cache items when going into background.
-Refactored and restructured all LocalItem related fragments and dialogs.
-Added error logging to unmonitored single-use observables.
-Modified playlist metadata query to return by alphabetical order.
-Removed sending toast when playlist is renamed or deleted as it is obvious.
-Removed unused code in main fragment.
2018-02-07 19:24:35 -08:00
John Zhen Mo
75a58d6381 -Fixed memory leak on rogue observable in history fragment.
-Removed stream id from playlist stream join table since only foreign constraint is needed.
-Added bar to playlist control UI.
-Modified local playlist fragment to no longer save when out of focus.
2018-02-07 19:24:35 -08:00
John Zhen Mo
62814f083e -Fixed memory leak in playlist append dialog due to rogue flowables.
-Changed image loader memory cache to use limited LRU.
2018-02-07 19:24:35 -08:00
John Zhen Mo
6f9deea873 -Fixed memory leak due to image loader overusing memory cache.
-Added disk cache for local item loading.
2018-02-07 19:24:35 -08:00
John Zhen Mo
d3160eed9d -Added state saving for streams on skip and player exception events.
-Added query for loading saved stream states.
-Modified orphan record removal to no longer consider stream table records.
2018-02-07 19:24:35 -08:00
John Zhen Mo
9b4a07de34 -Redone control panel in video detail fragment.
-Added playlist append menu item to channel and playlist fragments.
-Added debouncing to local playlist fragment to allow saving join when list is reordered or item is deleted.
-Extracted hardcoded strings.
2018-02-07 19:24:35 -08:00
John Zhen Mo
d31eeac49e -Condensed repeating entries on stream history.
-Changed search history to show service name and stream history to show repeat count.
-Removed history entry abstract and unused info items.
2018-02-07 19:24:35 -08:00
John Zhen Mo
84c5d27416 -Revamped local items to display more information such as service name, etc.
-Enabled reordering, renaming, removing of items on playlist fragment.
-Enabled removal of dangling streams entries when history is cleared.
-Changed playlist append menu item to icon on service player activity.
-Added adapter and builder for local items, removed dependency on infoitem and existing infolist for database entry items.
-Removed watch history entity and DAO.
-Extracted info item selected listener to remove adding boilerplate code when long click functionality is optional.
-Fixed query returning no record on left join when right table is empty.
2018-02-07 19:24:35 -08:00
John Zhen Mo
17d77aa31f -Removed watch history table.
-Added migration for dropping watch history table.
2018-02-07 19:24:35 -08:00
John Zhen Mo
388ec3e3d3 -Added history record manager as single entry for all database history transactions.
-Merged stream record manager into history record manager.
-Removed subject-based history database actions.
-Merged normalized history table into watch history fragment.
-Modified history fragments to use long click for delete actions.
-Refactored DAO operations from search fragment to record manager.
-Added index to search history table on search string.
-Fix baseplayer round repeat not detected by discontinuity.
2018-02-07 19:24:35 -08:00
John Zhen Mo
f0829f9ef3 -Added support for changing local playlist name and thumbnail url.
-Added query to remove stream table orphans.
-Added query for retrieving flattened watch history records.
-Added holder for local playlist stream info items.
-Refactored info item on select listener as on touch gesture.
2018-02-07 19:24:35 -08:00
John Zhen Mo
81f481833c -Added icon for bookmark pager. 2018-02-07 19:24:35 -08:00
John Zhen Mo
a74c4168f3 -Improved bulk stream upsert into playlist performance by 5x.
-Added custom info item type for plain stream entity.
2018-02-07 19:24:34 -08:00
John Zhen Mo
776dbc34f7 -Added bulk playlist creation and append.
-Added UI to create playlist from service player activity.
-Added state saving to playlist dialogs.
-Removed access to history activity on service player activity.
-Made StreamEntity serializable.
2018-02-07 19:24:34 -08:00
John Zhen Mo
168ac91ab8 -Fixed toast exception on playlist creation. 2018-02-07 19:24:34 -08:00
John Zhen Mo
9bd26798b6 -Added icon for adding stream to playlist.
-Renamed HistoryPlaylistFragment to StatisticsPlaylistFragment.
2018-02-07 19:24:34 -08:00
John Zhen Mo
4ae81a2de4 -Deprecating database get instance without context.
-Added comments to migrations.
2018-02-07 19:24:34 -08:00
John Zhen Mo
3c314ced0a -Bump database version to 2.
-Added migration script for upgrading database from version 1 to 2.
-Fixed database name of stream type in stream entity.
2018-02-07 19:24:34 -08:00
John Zhen Mo
ba9d0d7707 -Added basic UI for local playlists.
-Added UI for watch history and most played fragments.
-Added stream state table for storing playback timestamp and future usage.
-Enabled playlist deletion.
2018-02-07 19:24:34 -08:00
John Zhen Mo
38946e4b0f -Added UI for creating playlist.
-Added UI for appending item to playlists.
-Added mini variant of playlist info item.
2018-02-07 19:24:34 -08:00
John Zhen Mo
f71242a036 -Added schema for local playlist and stream statistics.
-Added normalized schema for stream history.
-Added managers for specialized database access for stream and local playlist.
2018-02-07 19:24:34 -08:00
Rintaro matsuo
960fd9be38 Translated using Weblate (Japanese)
Currently translated at 72.4% (200 of 276 strings)
2018-02-08 02:19:25 +01:00
ScratchBuild
40844dcd76 Translated using Weblate (Japanese)
Currently translated at 72.4% (200 of 276 strings)
2018-02-08 02:18:59 +01:00
Rintaro matsuo
420d28c713 Translated using Weblate (Japanese)
Currently translated at 72.4% (200 of 276 strings)
2018-02-08 02:17:54 +01:00
Weblate
5bbd6afaf1 Merge remote-tracking branch 'origin/dev' into dev 2018-02-08 02:17:40 +01:00
r2308145
77a06c7604 Translated using Weblate (Czech)
Currently translated at 100.0% (276 of 276 strings)
2018-02-08 02:17:38 +01:00
ezjerry liao
1f4f87d3bd Translated using Weblate (Chinese (Traditional))
Currently translated at 95.6% (264 of 276 strings)
2018-02-08 02:17:38 +01:00
thami simo
2e8d86575e Translated using Weblate (Arabic)
Currently translated at 94.2% (260 of 276 strings)
2018-02-08 02:17:35 +01:00
ScratchBuild
ef0659f436 Translated using Weblate (Japanese)
Currently translated at 72.4% (200 of 276 strings)
2018-02-08 02:17:33 +01:00
Christian Schabesberger
e18e69966f Merge pull request #1077 from TeamNewPipe/revert-1076-patch-1
Revert "Control media volume with the hardware buttons."
2018-02-07 21:39:19 +01:00
Christian Schabesberger
e7b4b88055 Revert "Control media volume with the hardware buttons." 2018-02-07 19:38:57 +01:00
Christian Schabesberger
de65d1e1fc Merge pull request #1076 from wojcik-online/patch-1
Control media volume with the hardware buttons.
2018-02-07 19:38:22 +01:00
wójcik.online
7ea0862f95 import AudioManager 2018-02-07 19:35:04 +01:00
wójcik.online
efc7049dfd Control media volume with the hardware buttons.
Control media volume with the hardware buttons in the MainActivity. This is how the YouTube app works. Closes #1072.
2018-02-07 19:24:25 +01:00
r2308145
629549d76f Translated using Weblate (Czech)
Currently translated at 100.0% (276 of 276 strings)
2018-02-07 19:19:31 +01:00
Oleh Ilnytskyi
756fb795d6 Translated using Weblate (Ukrainian)
Currently translated at 68.8% (190 of 276 strings)
2018-02-07 15:41:38 +01:00
BurningKarl
13d1974a5b Translated using Weblate (German)
Currently translated at 99.2% (274 of 276 strings)
2018-02-07 14:36:33 +01:00
wb9688
d3168a9022 Fix opening SoundCloud links 2018-02-07 10:22:27 +01:00
Freddy Morán Jr
059378eedf Translated using Weblate (Spanish)
Currently translated at 100.0% (276 of 276 strings)
2018-02-06 20:07:07 +01:00
Nathan Follens
e973868a90 Translated using Weblate (Dutch)
Currently translated at 100.0% (276 of 276 strings)
2018-02-06 12:23:33 +01:00
Emanuele Petriglia
2a0e5d6835 Translated using Weblate (Italian)
Currently translated at 100.0% (276 of 276 strings)
2018-02-06 09:53:09 +01:00
Weblate
5537abe2c3 Merge remote-tracking branch 'origin/dev' into dev 2018-02-05 22:40:19 +01:00
Oleh Ilnytskyi
5eae235b3c Translated using Weblate (Ukrainian)
Currently translated at 38.2% (102 of 267 strings)
2018-02-05 22:40:18 +01:00
ezjerry liao
bfc7718a21 Translated using Weblate (Chinese (Traditional))
Currently translated at 86.1% (230 of 267 strings)
2018-02-05 22:40:10 +01:00
TotalCaesar659
405d6bee78 Translated using Weblate (Russian)
Currently translated at 94.3% (252 of 267 strings)
2018-02-05 22:40:07 +01:00
Christian Schabesberger
f65f2da890 moved on to v0.11.6 2018-02-04 18:40:45 +01:00
Christian Schabesberger
30ab58c33d added some more lambdas 2018-02-04 17:50:22 +01:00
Christian Schabesberger
87ba5a7eb6 Merge branch 'eximport' into dev 2018-02-04 13:40:03 +01:00
Christian Schabesberger
6e8593af91 add import database function
bla

remove unused restart function

add allert dialog and add time to filename
2018-02-04 13:38:58 +01:00
Weblate
0ab1d3fc40 Merge remote-tracking branch 'origin/dev' into dev 2018-02-04 03:36:15 +01:00
ezjerry liao
f22d13e695 Translated using Weblate (Chinese (Traditional))
Currently translated at 83.5% (223 of 267 strings)
2018-02-04 03:36:07 +01:00
Mauricio Colli
cdde61a460 Change service icons for now
- Use place holders while the legal discussion is happening
2018-02-03 22:32:01 -02:00
Mauricio Colli
989ce126f1 Improve up button behavior
- Closes #614
2018-02-03 09:03:55 -02:00
ScratchBuild
28618e822e Translated using Weblate (Japanese)
Currently translated at 74.5% (199 of 267 strings)
2018-02-03 08:38:18 +01:00
Weblate
6772381afc Merge remote-tracking branch 'origin/dev' into dev 2018-01-31 13:34:27 +01:00
孟武尼德霍格龍
75b45beabc Translated using Weblate (Chinese (Traditional))
Currently translated at 77.2% (207 of 268 strings)
2018-01-31 13:34:24 +01:00
ButterflyOfFire
56d53e9b01 Translated using Weblate (Arabic)
Currently translated at 95.1% (255 of 268 strings)
2018-01-31 13:34:15 +01:00
Mauricio Colli
3a8b04e2d1 Fix and improve service switching (introduced colors)
- Every service now have its own colors
- Fix bug navigation button and backstack count
- Fix and themed properly the icons and colors of the main fragment tabs
- Re-organized the styles and colors (too much in one file)
2018-01-30 05:07:40 -02:00
Christian Schabesberger
1ce7d66fb1 Merge pull request #1043 from TobiGr/preferred-string
Make preferred string not translatable
2018-01-29 00:47:55 +01:00
TobiGr
7b5a9b69fe make preferred string not translatable 2018-01-28 21:27:20 +01:00
Allan Nordhøy
837b22ccac Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (268 of 268 strings)
2018-01-28 19:24:39 +01:00
Christian Schabesberger
7146719393 add export newipe db function 2018-01-28 19:02:34 +01:00
Weblate
71ee604c69 Merge remote-tracking branch 'origin/dev' into dev 2018-01-27 21:19:32 +01:00
Mateusz
9945a5b813 Translated using Weblate (Polish)
Currently translated at 98.1% (263 of 268 strings)
2018-01-27 21:19:31 +01:00
Kompiuterių meistras +37060040
7254387042 Translated using Weblate (Lithuanian)
Currently translated at 91.0% (244 of 268 strings)
2018-01-27 21:19:29 +01:00
Jonas
3a7f2a94a6 Translated using Weblate (French)
Currently translated at 100.0% (268 of 268 strings)
2018-01-27 21:19:26 +01:00
Mauricio Colli
6bea4aa96b Fix player switching
- Background to popup wasn't asking for permission
- The new task flag is needed to switch from the background/popup UI to the main player
2018-01-27 02:57:00 -02:00
Mauricio Colli
fa262bbceb Improve settings theme color
- Closes #863
2018-01-27 02:56:10 -02:00
Eduardo Caron
3139fe0170 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (265 of 268 strings)
2018-01-25 22:39:19 +01:00
Freddy Morán Jr
ef6c5de65b Translated using Weblate (Spanish)
Currently translated at 100.0% (268 of 268 strings)
2018-01-25 19:40:22 +01:00
M1ck
07799563b5 Translated using Weblate (French)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 18:36:21 +01:00
Nathan Follens
b1de4b7bd6 Translated using Weblate (Dutch)
Currently translated at 100.0% (268 of 268 strings)
2018-01-25 18:16:29 +01:00
E T
2b8ae9a5ea Translated using Weblate (Turkish)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:42:33 +01:00
Georg Rieger
7c52d3ec5d Translated using Weblate (German)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:37:17 +01:00
Osoitz
aefaa7619e Translated using Weblate (Basque)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:34:34 +01:00
Emanuele Petriglia
ca202290bf Translated using Weblate (Italian)
Currently translated at 100.0% (268 of 268 strings)
2018-01-24 14:46:59 +01:00
Weblate
cbdbc4cba2 Merge remote-tracking branch 'origin/dev' into dev 2018-01-24 13:10:42 +01:00
M1ck
8abf904a78 Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-24 13:10:32 +01:00
Mauricio Colli
ecf7969c46 Improve settings up button behavior
- Fix #736
2018-01-23 11:45:41 -02:00
Mauricio Colli
a473e3d623 Add preferred player 2018-01-23 11:15:36 -02:00
Weblate
1f8e90858e Merge remote-tracking branch 'origin/dev' into dev 2018-01-23 12:17:34 +01:00
Osoitz
2c2edca8fa Translated using Weblate (Spanish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:33 +01:00
Rubix
50e86ff1ca Translated using Weblate (Romanian)
Currently translated at 87.6% (221 of 252 strings)
2018-01-23 12:17:33 +01:00
Rintaro matsuo
02ecc5011a Translated using Weblate (Japanese)
Currently translated at 78.9% (199 of 252 strings)
2018-01-23 12:17:32 +01:00
nautilusx
6e666a018b Translated using Weblate (German)
Currently translated at 96.8% (244 of 252 strings)
2018-01-23 12:17:31 +01:00
M2ck
66fbb2ce1e Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:30 +01:00
r2308145
b00722ec0a Translated using Weblate (Czech)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:29 +01:00
ButterflyOfFire
77b1413319 Translated using Weblate (Arabic)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:29 +01:00
Osoitz
87b8d60c9d Translated using Weblate (Basque)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:26 +01:00
Christian Schabesberger
db5203e1ff Merge pull request #1023 from TobiGr/update-screenshots
Update screenshots
2018-01-23 00:27:28 +01:00
TobiGr
ea022670c4 Update screenshots 2018-01-22 21:04:27 +01:00
r2308145
54b009cc49 Translated using Weblate (Czech)
Currently translated at 100.0% (252 of 252 strings)
2018-01-22 19:09:37 +01:00
E T
80c3acace9 Translated using Weblate (Turkish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 17:40:52 +01:00
Nathan Follens
cea9428b47 Translated using Weblate (Dutch)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 17:34:51 +01:00
Emanuele Petriglia
f8ffbfabbe Translated using Weblate (Italian)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 12:12:04 +01:00
Allan Nordhøy
836a1e652b Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:27:15 +01:00
Freddy Morán Jr
d8544e0b84 Translated using Weblate (Spanish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:06:06 +01:00
M2ck
4817d7fddc Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:00:00 +01:00
ButterflyOfFire
e6a385a85e Translated using Weblate (Arabic)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 21:34:50 +01:00
Weblate
3634f68364 Merge remote-tracking branch 'origin/dev' into dev 2018-01-20 21:31:01 +01:00
Freddy Morán Jr
f17ffa94fe Translated using Weblate (Spanish)
Currently translated at 100.0% (249 of 249 strings)
2018-01-20 21:31:00 +01:00
Coffeemaker
d52bcd46a1 Translated using Weblate (German)
Currently translated at 97.5% (243 of 249 strings)
2018-01-20 21:30:56 +01:00
ButterflyOfFire
7e58b0b6fe Translated using Weblate (Arabic)
Currently translated at 100.0% (249 of 249 strings)
2018-01-20 21:30:49 +01:00
Christian Schabesberger
f451f1f65d resolve conflict 2018-01-20 18:06:34 +01:00
Christian Schabesberger
4d12e71fba move on to v0.11.5 2018-01-20 16:00:39 +01:00
Christian Schabesberger
66fde7a212 fix loop in channel 2018-01-20 15:59:34 +01:00
Christian Schabesberger
86eccf219d refactore some more lambda functions 2018-01-20 15:24:45 +01:00
Christian Schabesberger
677865f347 player popup menu icons for white theme 2018-01-20 14:46:10 +01:00
Christian Schabesberger
eb4b3810e9 refactor ExtractionHelper using lambda expression 2018-01-20 13:57:31 +01:00
Christian Schabesberger
5f26501ddf fix triangle play button when returning to app 2018-01-20 13:39:06 +01:00
Emanuele Petriglia
b33a72f864 Translated using Weblate (Italian)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 20:07:50 +01:00
Freddy Morán Jr
675f43b968 Translated using Weblate (Spanish)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 01:24:52 +01:00
M2ck
9f117a2e59 Translated using Weblate (French)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 00:33:40 +01:00
Yann Hodiesne
a0844229a3 Translated using Weblate (French)
Currently translated at 97.9% (244 of 249 strings)
2018-01-19 00:23:06 +01:00
M2ck
114fcc144c Translated using Weblate (French)
Currently translated at 97.9% (244 of 249 strings)
2018-01-19 00:19:11 +01:00
Weblate
43372ff648 Merge remote-tracking branch 'origin/dev' into dev 2018-01-19 00:17:53 +01:00
ScratchBuild
b8ebbc5404 Translated using Weblate (Japanese)
Currently translated at 79.5% (194 of 244 strings)
2018-01-19 00:17:51 +01:00
M2ck
28309f82f3 Translated using Weblate (French)
Currently translated at 100.0% (244 of 244 strings)
2018-01-19 00:17:45 +01:00
Christian Schabesberger
c70fa391b6 fix conflict with weblate 2018-01-18 20:43:30 +01:00
nautilusx
caab589dce Translated using Weblate (German)
Currently translated at 99.5% (243 of 244 strings)
2018-01-18 08:18:08 +01:00
maruyuki
20370054e7 Translated using Weblate (Japanese)
Currently translated at 56.9% (139 of 244 strings)
2018-01-18 08:18:04 +01:00
anonymous
f1882cb1e1 Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-12 19:37:15 +01:00
Nick Undnick
2ed149852d Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-10 18:22:38 +01:00
Coffeemaker
ac7226a0df Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-10 18:22:00 +01:00
Coffeemaker
5705650ca8 Translated using Weblate (Telugu)
Currently translated at 53.6% (131 of 244 strings)
2018-01-09 17:53:16 +01:00
Coffeemaker
60855ca7c5 Translated using Weblate (Tamil)
Currently translated at 5.7% (14 of 244 strings)
2018-01-09 17:53:16 +01:00
Coffeemaker
b8d8d181f3 Translated using Weblate (Slovak)
Currently translated at 70.0% (171 of 244 strings)
2018-01-09 17:53:16 +01:00
Thomas Lavend'Homme
6309160fc6 Translated using Weblate (French)
Currently translated at 100.0% (244 of 244 strings)
2018-01-09 17:53:14 +01:00
ButterflyOfFire
fc0e6ed273 Translated using Weblate (Arabic)
Currently translated at 100.0% (244 of 244 strings)
2018-01-09 17:53:04 +01:00
Christian Schabesberger
ada0cee656 move on to v0.11.4 2018-01-09 14:11:37 +01:00
Christian Schabesberger
6dde524d2c Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2018-01-09 14:02:39 +01:00
Christian Schabesberger
6a631e1915 forece select activity when opening with browser 2018-01-09 14:02:32 +01:00
Christian Schabesberger
bb6fa343cf Merge pull request #976 from coffeemakr/feature-share-subject
Add subject to shared URL's (fixes #975)
2018-01-09 13:53:29 +01:00
Christian Schabesberger
7557acde6c Merge pull request #977 from TobiGr/TranslationChecker-Fix
Fix crash due to no "other" item in plurals
2018-01-09 13:51:14 +01:00
TobiGr
25ed8952f9 Fix crash due to no "other" item in plurals 2018-01-09 13:24:50 +01:00
Coffeemakr
b93d94b0bd Add subject to shared URL's (fixes #975) 2018-01-09 12:41:30 +01:00
Christian Schabesberger
33d75fd2fb switch languageCode to content country 2018-01-09 12:25:40 +01:00
Christian Schabesberger
28a9855fd2 add countrycodes 2018-01-09 11:33:17 +01:00
Christian Schabesberger
9aad07621c fix many/other problem 2018-01-09 10:28:28 +01:00
Christian Schabesberger
384cde6eaa fix weblate merge failure 2018-01-08 13:29:25 +01:00
Sebastian Rasmussen
5ae98661ad Translated using Weblate (Swedish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-08 13:21:19 +01:00
Alberto Moshpirit
8f4d9ceca9 Translated using Weblate (Spanish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-08 13:21:15 +01:00
Christian Schabesberger
83d9a1233e horrible hack for fixing channel load next page foo 2018-01-06 20:39:33 +01:00
thami simo
522a287d79 Translated using Weblate (Arabic)
Currently translated at 96.3% (235 of 244 strings)
2018-01-06 17:21:06 +01:00
Sebastian Rasmussen
e052d4660d Translated using Weblate (Swedish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-06 17:21:03 +01:00
John Zhen Mo
39b0b2f032 -Added player conversion to background and popup players.
-[#919] Fixed custom notification does not trigger unlocking on lockscreen.
-[#947] Fixes player crashing on internet outage, issue partially addressed.
-Fixed main player losing state after destroy while in background.
-Fixed main player controls not hiding automatically after orientation change.
-Fixed dialog uploader not marqueeing when too long.
-Fixed popup permission throwing NPE on BaseList.
-Refactored popup permissions to start in NavigationHelper.
-Extracted hardcoded string for player menus.
-Bump Java version to 1.8.
-Some lambda conversions.
2018-01-03 22:53:38 -08:00
Christian Schabesberger
0223d6d200 moved on to v0.11.3 2018-01-04 05:34:19 +01:00
Christian Schabesberger
808ce72078 fix share menu for playlists 2018-01-04 05:28:01 +01:00
Christian Schabesberger
3a84c47176 hopefully fix plurals 2018-01-04 04:56:45 +01:00
Weblate
20c2426128 Merge remote-tracking branch 'origin/dev' into dev 2017-12-30 19:06:47 +01:00
Phạm Nguyễn Hoàng
bf11d4c9fa Translated using Weblate (Vietnamese)
Currently translated at 59.0% (144 of 244 strings)
2017-12-30 19:06:47 +01:00
Matej U
783c0f79d7 Translated using Weblate (Slovenian)
Currently translated at 91.8% (224 of 244 strings)
2017-12-30 19:06:46 +01:00
Ivan Krušlin
98b94bd9c4 Translated using Weblate (Croatian)
Currently translated at 97.1% (237 of 244 strings)
2017-12-30 19:06:44 +01:00
Rex_sa
ff0178f965 Translated using Weblate (Arabic)
Currently translated at 91.8% (224 of 244 strings)
2017-12-30 19:06:41 +01:00
Schabi
7f88c3d0a9 roleback wrong fix 2017-12-30 00:27:29 +01:00
Schabi
11e8e38f2c setup context for making notifications open via setContextIntent() 2017-12-29 17:29:15 +01:00
Schabi
50c5314eaf fix yt trending content language 2017-12-29 15:02:23 +01:00
Schabi
a7a76d4f58 add beta 2 logo 2017-12-26 14:48:06 +01:00
Schabi
4df4f68fe1 Merge branch 'dev' 2017-12-24 12:17:55 +01:00
Schabi
7db8d37137 update extractor and move on to version v0.11.2 2017-12-24 12:17:41 +01:00
Christian Schabesberger
b7503a7d81 Merge pull request #936 from TobiGr/readme-website
Add website, blog and press kit to README.MD
2017-12-23 17:47:59 +01:00
Schabi
9f5d4034e3 fix fullscreen button on popup 2017-12-23 17:34:47 +01:00
Tobias Groza
3c941f6c4b Add website, blog and press kit to README.MD 2017-12-23 16:35:40 +01:00
Christian Schabesberger
ec8fff421a fix avatar not vissible on info screen bug 2017-12-22 16:53:43 +01:00
Christian Schabesberger
a47a0b5432 Merge pull request #904 from Jawnnypoo/tweaks
Pull up support lib version so all always match
2017-12-22 15:25:33 +01:00
Christian Schabesberger
96ba46f21d Merge pull request #931 from TobiGr/notification-icon
Change notification bar icon for popup and background player
2017-12-21 16:03:15 +01:00
Ariel Shulman
90f48d5817 Translated using Weblate (Hebrew)
Currently translated at 100.0% (244 of 244 strings)
2017-12-20 23:47:19 +01:00
Jonas
7288dd097a Translated using Weblate (Spanish)
Currently translated at 100.0% (244 of 244 strings)
2017-12-20 17:02:16 +01:00
TobiGr
0119d62a35 change notification bar icon for popup and background player 2017-12-20 16:29:32 +01:00
Kompiuterių meistras +37060040
4d6ab73fa9 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (244 of 244 strings)
2017-12-20 13:06:09 +01:00
anonymous
f58c95840a Translated using Weblate (Lithuanian)
Currently translated at 60.6% (148 of 244 strings)
2017-12-20 11:04:43 +01:00
Weblate
ecf24f81ec Merge remote-tracking branch 'origin/dev' into dev 2017-12-18 14:15:55 +01:00
Rex_sa
dd3306a940 Translated using Weblate (Arabic)
Currently translated at 91.3% (223 of 244 strings)
2017-12-18 14:15:52 +01:00
Claudio Maradonna
bbb2b98f27 Translated using Weblate (Italian)
Currently translated at 100.0% (244 of 244 strings)
2017-12-18 14:15:32 +01:00
Christian Schabesberger
bc7332780d fix show rending before page was loaded 2017-12-17 12:55:30 +01:00
Joseph Kim
6f3bc3ac8f Translated using Weblate (Korean)
Currently translated at 99.5% (243 of 244 strings)
2017-12-14 11:48:42 +01:00
Weblate
cd04d869b7 Merge remote-tracking branch 'origin/dev' into dev 2017-12-12 15:49:41 +01:00
Eduardo Caron
909e15cbdd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (244 of 244 strings)
2017-12-12 15:49:31 +01:00
Christian Schabesberger
33fa30ab78 Merge branch 'feature-small-code-improvements' of https://github.com/coffeemakr/NewPipe into coffe 2017-12-11 18:06:38 +01:00
Anthony MARGERAND
44933ac17a Translated using Weblate (French)
Currently translated at 100.0% (244 of 244 strings)
2017-12-10 16:35:06 +01:00
Coffeemakr
bb2af96deb Use getters for extractor items 2017-12-10 11:07:51 +01:00
Coffeemakr
1fe6da14ea Small code improvements 2017-12-10 11:07:08 +01:00
Weblate
b7b9653c21 Merge remote-tracking branch 'origin/dev' into dev 2017-12-09 18:07:20 +01:00
alekksander
8adc5918f8 Translated using Weblate (Polish)
Currently translated at 100.0% (244 of 244 strings)
2017-12-09 18:07:19 +01:00
Tobias Groza
0db593b1bb Translated using Weblate (German)
Currently translated at 100.0% (244 of 244 strings)
2017-12-09 18:07:10 +01:00
Christian Schabesberger
a0c9dbeb78 Merge pull request #910 from coffeemakr/bugfix-integrate-extractor
Fix failing test
2017-12-09 17:36:13 +01:00
Nathan Follens
61d5546d89 Translated using Weblate (Dutch)
Currently translated at 100.0% (244 of 244 strings)
2017-12-09 14:30:18 +01:00
alekksander
f97b7c943b Translated using Weblate (Polish)
Currently translated at 100.0% (244 of 244 strings)
2017-12-09 13:58:19 +01:00
Duppadaadadii
97549b633b Translated using Weblate (Finnish)
Currently translated at 100.0% (244 of 244 strings)
2017-12-09 10:54:55 +01:00
Sérgio Marques
1949e4a9d4 Translated using Weblate (Portuguese)
Currently translated at 93.4% (228 of 244 strings)
2017-12-09 02:49:06 +01:00
Coffeemakr
ecb5f7a5ba Try Travis' solution 2017-12-08 20:26:44 +01:00
Emanuele Petriglia
6021f72cf0 Translated using Weblate (Italian)
Currently translated at 99.1% (242 of 244 strings)
2017-12-08 16:49:42 +01:00
nailyk
c00ef74f96 Translated using Weblate (French)
Currently translated at 99.5% (243 of 244 strings)
2017-12-08 14:46:23 +01:00
Coffeemakr
962e070150 Use Mediaformat objects instead of ids for tests 2017-12-08 13:57:44 +01:00
r2308145
221cbf5e07 Translated using Weblate (Czech)
Currently translated at 100.0% (244 of 244 strings)
2017-12-08 13:45:20 +01:00
Weblate
a72d37ab69 Merge remote-tracking branch 'origin/dev' into dev 2017-12-07 12:40:55 +01:00
E T
f92227e5df Translated using Weblate (Turkish)
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 12:40:54 +01:00
Eduardo Caron
c50617452f Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 12:40:52 +01:00
Allan Nordhøy
3957eca94d Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 12:40:51 +01:00
Tobias Groza
70111cf614 Translated using Weblate (German)
Currently translated at 99.5% (243 of 244 strings)
2017-12-07 12:40:49 +01:00
r2308145
f9e03c9a40 Translated using Weblate (Czech)
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 12:40:45 +01:00
Christian Schabesberger
88fbdf1cc4 Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2017-12-07 11:36:05 +01:00
Christian Schabesberger
7b76bd79e8 fix swaped name/url for channel 2017-12-07 11:33:34 +01:00
Allan Nordhøy
f4b58e649d Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 01:27:39 +01:00
John
91ff301d53 Pull up support lib version so all always match 2017-12-06 18:19:56 -06:00
Eduardo Caron
f5e1c99259 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 01:12:44 +01:00
Enol P
abdcd3cc30 Translated using Weblate (Asturian)
Currently translated at 100.0% (244 of 244 strings)
2017-12-07 00:57:40 +01:00
Weblate
23615a39ac Merge remote-tracking branch 'origin/dev' into dev 2017-12-07 00:52:53 +01:00
r2308145
5fa5fc39fc Translated using Weblate (Czech)
Currently translated at 100.0% (239 of 239 strings)
2017-12-07 00:52:50 +01:00
Enol P
01b3c7e91b Translated using Weblate (Asturian)
Currently translated at 100.0% (239 of 239 strings)
2017-12-07 00:52:42 +01:00
Christian Schabesberger
e4e364af3f move on to v0.11.1 2017-12-06 14:49:48 +01:00
Christian Schabesberger
f2358692af update to latest newpipeextractor 2017-12-06 14:29:26 +01:00
TobiGr
26ed6299e3 - add donation hint and website to about activity
- move NewPipe's license to license tab
2017-12-05 17:07:31 +01:00
Christian Schabesberger
3a85187111 Merge pull request #895 from TeamNewPipe/remember
remember last screen orientation
2017-12-05 12:59:00 +01:00
Christian Schabesberger
4261a2eed3 remember last screen orientation 2017-12-05 12:51:23 +01:00
antfarmer
fef17163a9 Translated using Weblate (Bulgarian)
Currently translated at 76.1% (182 of 239 strings)
2017-12-01 11:44:51 +01:00
Deva
9dd447a14f Translated using Weblate (Tamil)
Currently translated at 5.8% (14 of 239 strings)
2017-11-27 15:50:18 +01:00
r2308145
ecf4407ba4 Translated using Weblate (Czech)
Currently translated at 100.0% (239 of 239 strings)
2017-11-27 13:42:16 +01:00
antfarmer
039c0d3ee6 Translated using Weblate (Bulgarian)
Currently translated at 45.6% (109 of 239 strings)
2017-11-25 19:44:55 +01:00
antfarmer
5808aead55 Added translation using Weblate (Bulgarian) 2017-11-23 21:00:38 +01:00
Eduardo Caron
e797e2e7f1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (239 of 239 strings)
2017-11-23 20:58:37 +01:00
Weblate
23cacbfe65 Merge remote-tracking branch 'origin/dev' into dev 2017-11-23 19:46:19 +01:00
Massedil
4f94ee9b72 Translated using Weblate (French)
Currently translated at 100.0% (239 of 239 strings)

https://github.com/TeamNewPipe/NewPipe/issues/852
2017-11-23 19:46:16 +01:00
TheAssassin
0d1a26298a Recreate LICENSE
git revert screwed up so there was no LICENSE file at all any more, hence we have to recreate it.
2017-11-21 21:18:33 +01:00
TheAssassin
8ccd0b23e9 Revert "Create LICENSE"
This reverts commit d273f69852.
2017-11-21 21:14:52 +01:00
TheAssassin
9d8b991354 Revert "Rename LICENSE to LICENSE.txt"
This reverts commit eee3ccafc3.
2017-11-21 21:14:40 +01:00
TheAssassin
d273f69852 Create LICENSE 2017-11-21 16:06:47 +01:00
TheAssassin
eee3ccafc3 Rename LICENSE to LICENSE.txt
Should satisfy GitHub's license detection.
See https://help.github.com/articles/licensing-a-repository/ for details.
2017-11-21 15:15:07 +01:00
Allan Nordhøy
3686e90e81 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (239 of 239 strings)
2017-11-21 05:26:38 +01:00
wb9688
f5f8371865 Remove setting 2017-11-20 19:31:33 +01:00
wb9688
1191455d37 Show selected service 2017-11-20 16:04:18 +01:00
Andrey mm
1a5d9da2bf Translated using Weblate (Russian)
Currently translated at 99.5% (238 of 239 strings)
2017-11-20 04:49:02 +01:00
wb9688
011e151c91 Merge branch 'dev' into multiple-services 2017-11-19 17:41:57 +01:00
wb9688
54aa40eac1 Add simple drawer for selecting service 2017-11-19 17:21:46 +01:00
Andrey mm
21a7a73f6d Translated using Weblate (Russian)
Currently translated at 93.7% (224 of 239 strings)

changed according to format of "default audio" title
2017-11-18 08:40:20 +01:00
Andrey mm
5090b41eef Translated using Weblate (Russian)
Currently translated at 93.7% (224 of 239 strings)
2017-11-18 08:28:56 +01:00
ktln
0e55aa6249 Translated using Weblate (Russian)
Currently translated at 93.7% (224 of 239 strings)
2017-11-18 06:28:54 +01:00
Andrey mm
dd2dcf4df2 Translated using Weblate (Russian)
Currently translated at 93.7% (224 of 239 strings)
2017-11-18 06:28:20 +01:00
Oscar Hemelaar
2e84b28998 Translated using Weblate (French)
Currently translated at 100.0% (239 of 239 strings)
2017-11-17 22:46:13 +01:00
Oscar Hemelaar
e6cbfea5a7 Translated using Weblate (Spanish)
Currently translated at 100.0% (239 of 239 strings)
2017-11-16 22:05:00 +01:00
Weblate
641d662944 Merge remote-tracking branch 'origin/dev' into dev 2017-11-16 22:01:48 +01:00
Oscar Hemelaar
09208e183b Translated using Weblate (French)
Currently translated at 100.0% (239 of 239 strings)
2017-11-16 22:01:43 +01:00
Christian Schabesberger
fba3ece688 resolve conflict 2017-11-16 12:20:03 +01:00
Christian Schabesberger
f7d849a3cc Merge branch 'expiring_lru' of https://github.com/karyogamy/NewPipe into info 2017-11-16 11:55:39 +01:00
Allan Nordhøy
709c700cc6 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.5% (238 of 239 strings)
2017-11-16 07:48:32 +01:00
John Zhen Mo
2da411c1ec -#836: Modified notifications texts to use custom colors instead of device-specific styles. 2017-11-15 20:42:05 -08:00
John Zhen Mo
d6e4f3c809 -Saves the recovery timestamp when player source fails during a valid stream playback. 2017-11-15 20:09:38 -08:00
Freddy Morán Jr
1bb08db8ba Translated using Weblate (Spanish)
Currently translated at 98.7% (236 of 239 strings)
2017-11-15 19:49:38 +01:00
Daria Szatan
2ba116b1e6 Translated using Weblate (Polish)
Currently translated at 69.8% (167 of 239 strings)
2017-11-15 16:48:24 +01:00
lolloCreator
7088de0fb9 Translated using Weblate (Italian)
Currently translated at 100.0% (239 of 239 strings)
2017-11-15 16:47:12 +01:00
Duppadaadadii
7084f73d6c Translated using Weblate (Finnish)
Currently translated at 100.0% (239 of 239 strings)
2017-11-15 13:45:56 +01:00
John Zhen Mo
69374e25fe -Fixed cursor position to point to end after search text insert.
-Reduced and slightly changed offset of search text insert image.
2017-11-14 15:58:13 -08:00
John Zhen Mo
5e16969d61 -Increased search item insert arrow click space. 2017-11-14 11:34:17 -08:00
John Zhen Mo
0fe5a44e5a -Removed todo for timeout feature on info cache. 2017-11-14 11:34:16 -08:00
John Zhen Mo
98e617001d -Added search suggestion insert per #840. 2017-11-14 11:34:16 -08:00
John Zhen Mo
979bd09b29 -Fixed popup player not in foreground when opened by external intent.
-Fixed popup overlay permission causing exception when opened externally.
2017-11-14 11:34:15 -08:00
John Zhen Mo
77678b8f31 -Modified InfoItem LRU cache expire to allow expiration (current default 4 hours).
-Modified info type display on InfoItemDialog to show uploader name if exists.
2017-11-14 11:34:15 -08:00
lolloCreator
3575cac9d7 Translated using Weblate (Italian)
Currently translated at 100.0% (239 of 239 strings)
2017-11-14 16:40:51 +01:00
Weblate
8cdeaf1b27 Merge remote-tracking branch 'origin/dev' into dev 2017-11-14 13:23:41 +01:00
E T
08a8c6c414 Translated using Weblate (Turkish)
Currently translated at 100.0% (239 of 239 strings)
2017-11-14 13:23:40 +01:00
CookieCaptain D
fa5c1b22ae Translated using Weblate (Portuguese)
Currently translated at 95.8% (229 of 239 strings)
2017-11-14 13:23:34 +01:00
vipul jurel
a99e7f3288 Translated using Weblate (Hindi)
Currently translated at 100.0% (239 of 239 strings)
2017-11-14 13:23:32 +01:00
Duppadaadadii
a29506ed2f Translated using Weblate (Finnish)
Currently translated at 100.0% (239 of 239 strings)
2017-11-14 13:23:16 +01:00
Christian Schabesberger
1434b40d03 fix not compilling because of icepick 2017-11-14 12:14:01 +01:00
marin
6d6609187b Add dropdown menu and switch to background option 2017-11-13 20:29:54 +01:00
anonymous
9682eaae2a Translated using Weblate (Portuguese)
Currently translated at 92.4% (221 of 239 strings)
2017-11-13 19:48:08 +01:00
anonymous
1cdb4ccc17 Translated using Weblate (Portuguese)
Currently translated at 90.7% (217 of 239 strings)
2017-11-13 19:47:03 +01:00
CookieCaptain D
2a878dffbc Translated using Weblate (Portuguese)
Currently translated at 90.3% (216 of 239 strings)
2017-11-13 19:46:47 +01:00
anonymous
49f4fb7ed7 Translated using Weblate (Portuguese)
Currently translated at 89.9% (215 of 239 strings)
2017-11-13 19:46:31 +01:00
CookieCaptain D
caa985660a Translated using Weblate (Portuguese)
Currently translated at 89.1% (213 of 239 strings)
2017-11-13 19:45:46 +01:00
Weblate
3842a1e4fb Merge remote-tracking branch 'origin/dev' into dev 2017-11-13 18:41:49 +01:00
Matej U
e06d83cb93 Translated using Weblate (Slovenian)
Currently translated at 92.8% (222 of 239 strings)
2017-11-13 18:41:48 +01:00
Morten R
67df894448 Translated using Weblate (German)
Currently translated at 100.0% (239 of 239 strings)
2017-11-13 18:41:45 +01:00
Charles de Lacombe
d1ec6cf21b Translated using Weblate (French)
Currently translated at 94.5% (226 of 239 strings)
2017-11-13 18:41:43 +01:00
Enol P
537c561cee Translated using Weblate (Asturian)
Currently translated at 94.9% (227 of 239 strings)
2017-11-13 18:41:42 +01:00
Nathan Follens
a65ddc5b36 Translated using Weblate (Dutch)
Currently translated at 100.0% (239 of 239 strings)
2017-11-13 18:41:40 +01:00
Christian Schabesberger
1fb1b3a784 Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2017-11-12 23:58:29 +01:00
Christian Schabesberger
b80879765c Merge branch 'dev' of https://github.com/lawonga/NewPipe into fix 2017-11-12 23:58:08 +01:00
Weblate
10919fe15b Merge remote-tracking branch 'origin/dev' into dev 2017-11-12 21:52:51 +01:00
vipul jurel
9e5fe1edca Translated using Weblate (Hindi)
Currently translated at 100.0% (239 of 239 strings)
2017-11-12 21:52:50 +01:00
Mathias Norräng
03ee3f3d2a Translated using Weblate (Swedish)
Currently translated at 100.0% (239 of 239 strings)
2017-11-12 21:52:38 +01:00
Christian Schabesberger
4113283069 Merge pull request #833 from TeamNewPipe/fastlane
[WIP] add fastlane support
2017-11-12 21:34:10 +01:00
Mathias Norräng
56c5f696df Translated using Weblate (Swedish)
Currently translated at 61.0% (146 of 239 strings)
2017-11-12 21:12:20 +01:00
Weblate
9beb76e641 Merge remote-tracking branch 'origin/dev' into dev 2017-11-12 18:48:19 +01:00
YFdyh000
f71403be58 Translated using Weblate (Chinese (Simplified))
Currently translated at 87.4% (209 of 239 strings)
2017-11-12 18:48:16 +01:00
vipul jurel
d0e5d36b1b Translated using Weblate (Hindi)
Currently translated at 100.0% (239 of 239 strings)
2017-11-12 18:48:05 +01:00
Christian Schabesberger
fdeb7543ca fix channel rssbutton null pointer bug 2017-11-12 13:59:11 +01:00
Weblate
90716f4f5b Merge remote-tracking branch 'origin/dev' into dev 2017-11-12 13:22:06 +01:00
Ivan Krušlin
54d41bc288 Translated using Weblate (Croatian)
Currently translated at 100.0% (233 of 233 strings)
2017-11-12 13:22:05 +01:00
drgsh
d63c7a9042 Translated using Weblate (Hindi)
Currently translated at 25.7% (60 of 233 strings)
2017-11-12 13:22:01 +01:00
Christian Schabesberger
cd5b60cbed fix layout 2017-11-12 09:16:51 +01:00
Christian Schabesberger
6d60e6698a Merge branch 'play-queue-enhancement' of https://github.com/karyogamy/NewPipe into pqe 2017-11-12 08:33:05 +01:00
Christian Schabesberger
d53cb01396 add fastlane support
fix screenthots link

add description
2017-11-12 08:31:09 +01:00
lawonga
8baaecab1b #827 Fixes auto rotation bug with useAsFrontPage on by preserving the useAsFrontPage boolean setting 2017-11-11 19:51:20 -08:00
John Zhen Mo
1368f9f89e -Fixed channel header contrast color. 2017-11-11 15:05:48 -08:00
John Zhen Mo
ce36f3ae3b -Modified play queue action buttons on playlist and channel fragments.
-Added info item menu with custom title banner on long click.
-Enabled starting playlists and channels from middle.
-Enabled caching for play queue item thumbnails.
-Modified play queue to revert to first item on deleting last item.
2017-11-11 14:48:16 -08:00
John Zhen Mo
cf147aa161 -Reverted dropdown menu UI for list view info items. 2017-11-11 14:48:16 -08:00
John Zhen Mo
7700cff5e5 -Added play buttons to channel fragment similar to playlist fragment.
-Fixed abstract info play queue reloading the same initial page.
-Fixed OOB on get item for abstract play queue.
2017-11-11 14:48:16 -08:00
John Zhen Mo
b883f313ba -Fixed NPE when popup is updated during shutdown. 2017-11-11 14:48:16 -08:00
John Zhen Mo
b1ee22cde6 -Added scroll to fetch for external play queues.
-Modified service player activity scrolling to be instantaneous when difference is too large.
-Modified service player activity to no longer update metadata if nothing change when sync is called.
2017-11-11 14:48:16 -08:00
John Zhen Mo
b32f149a1b -Refactored Channel and Playlist PlayQueue into AbstractInfo playQueue.
-Increase list item action dropdown padding.
2017-11-11 14:48:16 -08:00
John Zhen Mo
1d136c6c35 -Added fast seeking on background notification when play queue size is 1.
-Fixed player intent with quality selection not used in detail fragment.
-Fixed window index not reset on sync when not playing.
-Fix dropdown play string for stream info item.
2017-11-11 14:48:16 -08:00
John Zhen Mo
b8a17580c5 -Added play queue dropdown to channel info items.
-Added play queue dropdown to playlist info items.
-Added Channel Play Queue.
-Renamed External Play Queue to Playlist Play Queue.
-Modified Playlist Play Queue to allow loading from initial state.
2017-11-11 14:48:16 -08:00
John Zhen Mo
87febf8679 -Added dropdown to start play for all StreamInfoItem.
-Refactored NavigationHelper to allow service player control to open anywhere.
-Refactored NavigationHelper to allow starting player at anywhere.
2017-11-11 14:48:16 -08:00
John Zhen Mo
38b2ffd450 -Added fling to toss popup view when velocity is below shutdown.
-Added string for unknown content.
-Fixed NPE when UI element is touched after player shuts down in service activity.
-Fixed shuffle reset caused by position discontinuity offsets index.
-Moved some more player shared preferences to PlayerHelper.
2017-11-11 14:48:16 -08:00
John Zhen Mo
01e031e7e7 -Modified recovery to not set if progress position is 0 or less.
-Modified queue item synchronization to no longer trigger update when the sync is run on the identical item.
2017-11-11 14:48:16 -08:00
John Zhen Mo
0b1eda3050 -Improved null checks in player stream resolution.
-Improved naming in MediaSourceManager
2017-11-11 14:48:16 -08:00
Weblate
52cdf96dfe Merge remote-tracking branch 'origin/dev' into dev 2017-11-11 18:55:55 +01:00
nautilusx
1f5eba59c5 Translated using Weblate (German)
Currently translated at 99.5% (232 of 233 strings)
2017-11-11 18:55:51 +01:00
r2308145
372c2f2be0 Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-11 18:55:48 +01:00
Ivan Krušlin
25e0b46396 Translated using Weblate (Croatian)
Currently translated at 100.0% (233 of 233 strings)
2017-11-11 18:55:45 +01:00
wb9688
621a1909ec Merge remote-tracking branch 'origin/dev' into multiple-services 2017-11-11 13:18:26 +01:00
Christian Schabesberger
d3332583b6 Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2017-11-10 21:31:39 +01:00
Christian Schabesberger
cb5cf9bb09 update support lib to 27.0.1 2017-11-10 21:31:19 +01:00
Nick Undnick
6cb2c2a84e Translated using Weblate (German)
Currently translated at 99.5% (232 of 233 strings)
2017-11-10 20:54:24 +01:00
nautilusx
633137fd79 Translated using Weblate (German)
Currently translated at 99.5% (232 of 233 strings)
2017-11-10 20:53:22 +01:00
Weblate
9627fdf33f Merge remote-tracking branch 'origin/dev' into dev 2017-11-10 20:46:38 +01:00
Praveen0899
b39366c80a Translated using Weblate (Telugu)
Currently translated at 72.5% (169 of 233 strings)
2017-11-10 20:46:38 +01:00
drgsh
ac01c49666 Translated using Weblate (Hindi)
Currently translated at 23.6% (55 of 233 strings)
2017-11-10 20:46:13 +01:00
r2308145
80d16ea407 Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-10 20:46:11 +01:00
Tobias Groza
4f44f26333 Translated using Weblate (German)
Currently translated at 99.5% (232 of 233 strings)
2017-11-10 20:46:08 +01:00
Christian Schabesberger
a21bdb1487 Merge branch 'studio-3' of https://github.com/wb9688/NewPipe into a 2017-11-10 20:45:05 +01:00
Christian Schabesberger
4d6a2f40d3 Merge pull request #830 from TobiGr/fix-ta-language-code
Fix Tamil language code
2017-11-10 19:47:12 +01:00
Nick Undnick
e6773aac0e Translated using Weblate (German)
Currently translated at 99.5% (232 of 233 strings)
2017-11-10 19:46:31 +01:00
TobiGr
997381d0c3 Fix Tamil language code 2017-11-10 16:57:58 +01:00
wb9688
ac53eeb76d Upgrade ACRA 2017-11-10 15:36:13 +01:00
wb9688
a09c8934fc Fix Travis 2017-11-10 15:34:57 +01:00
Ephraim Raj
b4120c39e6 Translated using Weblate (Hindi)
Currently translated at 21.8% (51 of 233 strings)
2017-11-10 13:46:37 +01:00
wb9688
5d6320d925 Upgrade to Studio 3 2017-11-10 10:33:59 +01:00
Xuacu Saturio
985bf50f7f Translated using Weblate (Asturian)
Currently translated at 96.5% (225 of 233 strings)
2017-11-09 22:44:19 +01:00
Allan Nordhøy
84d21af644 Translated using Weblate (Norwegian Bokmål)
Currently translated at 95.7% (223 of 233 strings)
2017-11-09 21:47:47 +01:00
Weblate
267cd99b04 Merge remote-tracking branch 'origin/dev' into dev 2017-11-08 19:49:19 +01:00
r2308145
401960079c Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-08 19:49:17 +01:00
Freddy Morán Jr
1fbc8a2850 Translated using Weblate (Spanish)
Currently translated at 98.7% (230 of 233 strings)
2017-11-08 19:49:08 +01:00
Christian Schabesberger
16fe5a94ac Merge pull request #821 from Stokkie64/patch-1
Update CONTRIBUTING.md
2017-11-08 13:02:34 +01:00
Arjen Singels
1c20a4d9eb Update CONTRIBUTING.md
fixed typo.
2017-11-08 13:58:01 +02:00
Christian Schabesberger
3a9f30d954 Merge pull request #812 from imallan/dev
Fixes ClassCastException when getting Bitmap from AdaptiveIcon
2017-11-08 12:55:07 +01:00
Christian Schabesberger
856aacf8ce Merge pull request #819 from TobiGr/fix-czech-plurals
Fix Czech plurals
2017-11-08 12:54:38 +01:00
TobiGr
441b510775 Fix plurals not showing number of views, videos and subscribers
Fix typo in pull request template
2017-11-07 14:48:48 +01:00
Weblate
88a10b5af1 Merge remote-tracking branch 'origin/dev' into dev 2017-11-07 11:44:38 +01:00
Duppadaadadii
65205ace95 Translated using Weblate (Finnish)
Currently translated at 100.0% (233 of 233 strings)
2017-11-07 11:44:37 +01:00
Nathan Follens
1a4ef06ee9 Translated using Weblate (Dutch)
Currently translated at 100.0% (233 of 233 strings)
2017-11-07 11:44:31 +01:00
r2308145
64ac631040 Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-07 11:44:30 +01:00
Omar
4e4cabb929 Translated using Weblate (Arabic)
Currently translated at 40.3% (94 of 233 strings)
2017-11-07 11:44:22 +01:00
Christian Schabesberger
b242c86869 add support for indian languages 2017-11-07 11:04:12 +01:00
vesp
d37fee346a Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 22:41:56 +01:00
r2308145
cc52d3b0af Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 22:41:07 +01:00
vesp
d5b1bae305 Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 22:39:44 +01:00
r2308145
04e22faf85 Translated using Weblate (Czech)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 22:38:51 +01:00
Nathan Follens
48cb3ed138 Translated using Weblate (Dutch)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 18:24:39 +01:00
wb9688
ebdeee8b3c Translated using Weblate (Dutch)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 18:21:29 +01:00
anonymous
6449d7d4ee Translated using Weblate (Dutch)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 18:20:08 +01:00
yilun
4b775d15a2 Fixes ClassCastException when getting Bitmap from AdaptiveIcon on Android 8+ 2017-11-06 12:27:10 +00:00
wb9688
e4d6a453b0 Translated using Weblate (Dutch)
Currently translated at 100.0% (233 of 233 strings)
2017-11-06 11:44:55 +01:00
anonymous
9dcbcd57cb Translated using Weblate (Arabic)
Currently translated at 33.4% (78 of 233 strings)
2017-11-06 10:36:44 +01:00
Omar
17aa44c88b Translated using Weblate (Arabic)
Currently translated at 33.4% (78 of 233 strings)
2017-11-06 10:36:32 +01:00
Weblate
60dc266e13 Merge remote-tracking branch 'origin/dev' into dev 2017-11-05 23:03:03 +01:00
Duppadaadadii
60ed308caa Translated using Weblate (Finnish)
Currently translated at 100.0% (233 of 233 strings)
2017-11-05 23:02:59 +01:00
Christian Schabesberger
c485e7e167 merge master 2017-11-05 21:00:05 +01:00
Christian Schabesberger
71a8361580 merge dev 2017-11-05 20:59:17 +01:00
Christian Schabesberger
666dce1b6f move on to version v0.11.0 2017-11-05 20:58:32 +01:00
Christian Schabesberger
7bed1c2295 merge weblate crash 2017-11-05 18:08:53 +01:00
Duppadaadadii
51325089f0 Translated using Weblate (Finnish)
Currently translated at 99.5% (232 of 233 strings)
2017-11-05 00:48:12 +01:00
Mladen Pejaković
90666a84ac Translated using Weblate (Serbian)
Currently translated at 99.1% (231 of 233 strings)
2017-11-05 00:48:10 +01:00
Christian Schabesberger
0c37bd3a64 Merge pull request #809 from TobiGr/fix-kosk-strings
Remove unused "service_kosk_string" strings
2017-11-03 21:59:21 +01:00
Weblate
753517fb56 Merge remote-tracking branch 'origin/dev' into dev 2017-11-03 21:45:03 +01:00
Ivan Krušlin
b939daac2a Translated using Weblate (Croatian)
Currently translated at 90.1% (210 of 233 strings)
2017-11-03 21:44:58 +01:00
TobiGr
8f2b7b2783 remove unused "service_kosk_string" strings 2017-11-03 18:58:19 +01:00
Christian Schabesberger
883d4b4065 Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2017-11-02 20:46:45 +01:00
Christian Schabesberger
ff38ae202b Merge branch 'fix-open-channel-url-in-browser' of https://github.com/coffeemakr/NewPipe into chan 2017-11-02 20:36:31 +01:00
Tobias Groza
7b71302a63 Translated using Weblate (German)
Currently translated at 97.8% (228 of 233 strings)
2017-11-02 18:46:20 +01:00
Duppadaadadii
cbf8fc5bb9 Translated using Weblate (Finnish)
Currently translated at 99.5% (232 of 233 strings)
2017-11-02 16:45:36 +01:00
Tobias Groza
00797a7834 Translated using Weblate (Lithuanian)
Currently translated at 60.9% (142 of 233 strings)
2017-11-02 08:11:42 +01:00
Coffeemaker
de092e5357 Translated using Weblate (German)
Currently translated at 97.8% (228 of 233 strings)
2017-11-01 18:30:50 +01:00
Georg Rieger
bba8739008 Translated using Weblate (German)
Currently translated at 96.5% (225 of 233 strings)
2017-11-01 16:45:26 +01:00
Coffeemaker
3c5564b274 Translated using Weblate (German)
Currently translated at 96.1% (224 of 233 strings)
2017-11-01 16:45:13 +01:00
Georg Rieger
f3ff24cfbf Translated using Weblate (German)
Currently translated at 95.7% (223 of 233 strings)
2017-11-01 16:44:52 +01:00
Tobias Groza
975b519585 Translated using Weblate (German)
Currently translated at 95.2% (222 of 233 strings)
2017-11-01 16:37:58 +01:00
Georg Rieger
7f1f34f812 Translated using Weblate (German)
Currently translated at 95.2% (222 of 233 strings)
2017-11-01 16:37:28 +01:00
Tobias Groza
d5bab1006e Translated using Weblate (German)
Currently translated at 91.8% (214 of 233 strings)
2017-11-01 16:32:26 +01:00
Coffeemakr
b52e48a355 Use provided url instead of channelInfo 2017-11-01 16:30:24 +01:00
Emanuele Petriglia
68a807a446 Translated using Weblate (Italian)
Currently translated at 100.0% (233 of 233 strings)
2017-11-01 13:17:25 +01:00
Weblate
0dc6b66825 Merge remote-tracking branch 'origin/dev' into dev 2017-11-01 12:14:16 +01:00
Anton Shestakov
a9db7616aa Translated using Weblate (Russian)
Currently translated at 95.2% (222 of 233 strings)
2017-11-01 12:14:15 +01:00
nailyk
b71e2833d6 Translated using Weblate (French)
Currently translated at 96.9% (226 of 233 strings)
2017-11-01 12:14:13 +01:00
blacklight
56bc919866 Translated using Weblate (Dutch)
Currently translated at 88.8% (207 of 233 strings)
2017-11-01 12:14:11 +01:00
Eduardo Caron
ac3d8cddbe Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (233 of 233 strings)
2017-11-01 12:14:03 +01:00
Christian Schabesberger
aa10b392ae Merge pull request #803 from coffeemakr/bugfix-play-from-sdcard
[WIP] Add root-path /storage (fixes #707)
2017-11-01 01:37:29 +01:00
Christian Schabesberger
e8ea1c92b1 Merge pull request #805 from karyogamy/notification-controls-intent-fix
Fixes Open Control intent exception between SDK 21 and 24
2017-11-01 01:37:15 +01:00
Weblate
b5d7b80fe9 Merge remote-tracking branch 'origin/dev' into dev 2017-10-31 20:46:09 +01:00
Joona Mattila
2a328e28da Translated using Weblate (Finnish)
Currently translated at 100.0% (219 of 219 strings)
2017-10-31 20:46:03 +01:00
Christian Schabesberger
3d1cc348c8 fix getUploaderName() and move on to v0.10.2 2017-10-31 19:47:46 +01:00
John Zhen Mo
3d5c173d61 -Fixed new task intent for opening controls on players between sdk 21 and 24. 2017-10-31 07:17:51 -07:00
Christian Schabesberger
9a5da5199d Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2017-10-31 14:18:46 +01:00
Christian Schabesberger
764a171a25 fix nullpinter exception for getUploaderName() 2017-10-31 14:18:38 +01:00
Coffeemakr
25061ab07c Add root-path /storage (fixes #707)
See
https://stackoverflow.com/questions/32333094/android-fileprovider-for-ext-sdcard
for why this solution migth work.
2017-10-31 12:14:44 +01:00
Christian Schabesberger
6074925102 Update README.md 2017-10-31 10:41:39 +01:00
Christian Schabesberger
f8c0c449bf Merge branch 'fature-log-kodi-videos' of https://github.com/coffeemakr/NewPipe into kodi 2017-10-31 10:08:28 +01:00
Coffeemakr
26d18c588e Implement channel menu (closes #759) 2017-10-31 09:25:27 +01:00
Coffeemakr
6f18dd26a2 Call history listener for Kodi (closes #798)
If Kore (the Kodi App) was sucessfully started the history listener is
invoked.
2017-10-31 07:47:14 +01:00
Coffeemakr
7340bc05b4 Small refactoring for Kore and Kodi
* Improve installation procedure
2017-10-31 07:45:53 +01:00
John Zhen Mo
b0948cf9fc -Modified selected play queue item to highlight entire item instead of text.
-Added selected item bullet.
-Modified play queue panel darker on main video player.
-Fixed color issue on play queue panel on light-themed main video player.
-Fixed hold-to-enqueue tooltip flashing when clicked on earlier sdk versions.
-Fixed queue item removal causing metadata for currently playing to refresh.
2017-10-30 20:59:21 -07:00
John Zhen Mo
86c16fa5d8 -Fixed activity padding.
-Fixed expanded notification artist name.
-Fixed playpause on complete setting wrong index.
2017-10-30 20:58:47 -07:00
John Zhen Mo
68695bbf92 -Modified MediaSourceManager to immediately load on critical events.
-Fixed tag name for background service actcivity.
-Removed unused track selector.
-Removed unused database entities.
2017-10-30 20:58:47 -07:00
John Zhen Mo
b4fdbdeb1b -Added load debouncing to MediaSourceManager to prevent mass loading due to rapid timeline change.
-Added marquee title to main video player.
-Modified destroyPlayer to always dispose play queue and media source manager.
-Remove unused code from players.
2017-10-30 20:58:47 -07:00
John Zhen Mo
1fb3774e03 -Changed play queue item building to shrink thumbnail before caching.
-Renamed refactor directory in player to helper.
-Fixed background player notification update causing lag on older spec models.
-Fixed service activity theme not changing after user setting is changed.
-Fixed NPE on popup player fling to close.
-Fixed audio reactor volume and max volume mixup.
-Added correct toast for each player error case.
-Fixed button coloring for play queue service activity on landscape.
-Changed title and uploader text to marquee for vertical service activity.
-Removed cache clearing on every thumbnail load.
2017-10-30 20:58:47 -07:00
John Zhen Mo
f284a799ef -Added wake and wifi lock to popup video player.
-Added seek time display to player binding activity.
-Added button effect for all image buttons on player binding activity.
-Added click to scroll to current selected on metadata layout for player binding activity.
-Refactored player utilities and preference getters into PlayerHelper.
-Refactored player caching into CacheFactory.
-Refactored player audio related methods into AudioReactor.
-Refactored player locks into LockManager.
-Refactored player loading and buffering mechanics into LoadController.
-Fixed outdated names for background player.
2017-10-30 20:58:47 -07:00
John Zhen Mo
c6e759a94c -Fixed popup player not playing in foreground.
-Fixed activity binder memory leak in popup and background players.
-Fixed out of bound window after removing last item on play queue.
-Fixed MediaSourceManager continues to process update after disposed.
-Changed play queue append to shuffle if queue is already shuffled.
2017-10-30 20:58:46 -07:00
John Zhen Mo
052c9a9869 -Added persisting settings when switching between players. 2017-10-30 20:58:46 -07:00
John Zhen Mo
0806344ffb -Changed quality resolution to persist across player.
-Updated ExoPlayer to 2.5.4.
-Expanded button size in main video player play queue.
-Removed Quality event.
-Extracted player error strings to xml.
2017-10-30 20:58:46 -07:00
John Zhen Mo
d0e626c6ee -Fixed popup and main video players not using different quality resolution. 2017-10-30 20:58:46 -07:00
John Zhen Mo
9068247856 -Reverted manual track selection from exoplayer track selector.
-Added quality record to play queue items.
-Added quality and recovery record play queue events.
-Added landscape view for ServicePlayerActivity.
-Moved repeat and shuffle button to play queue panel in main video player.
-Fixed potential NPE in MediaSourceManager by no longer nulling play queue on dispose.
-Renamed PlayQueueEvent to PlayQueueEventType.
-Renamed PlayQueueMessage to PlayQueueEvent.
2017-10-30 20:58:46 -07:00
John Zhen Mo
4553850412 -Baked recovery records into play queue items.
-Added previous and next button on main video player.
-Reverted double tap to seek for popup and main video players.
-Improved shuffling to use recovery record.
-Changed shuffling to place current playing stream to top of queue.
-Fixed exception when removing last item on queue.
-Changed fast forward and rewind button to previous and next on background notification.
-Changed background notification to not update when screen is off and update immediately when screen is turned back on.
-Removed unused intent strings.
-Changed "Append" to "Enqueue" for append text.
2017-10-30 20:58:46 -07:00
John Zhen Mo
21d42c92e5 -Reduced text size for hold to append tip.
-Added options to turn off hold to append tip.
2017-10-30 20:58:46 -07:00
John Zhen Mo
eb9770e3ba -Fixed set index ignoring selection to current index when queue at current index changed.
-Modified popup player to disable rendering when screen is off.
2017-10-30 20:58:46 -07:00
John Zhen Mo
d54a6e0b0e -Added helper text on click for background and popup button on detail fragment for feature discovery.
-Fixed popup video queuing causes existing popup player to change quality.
2017-10-30 20:58:45 -07:00
John Zhen M
a8f5cfa640 -Added different toast for append long click on detail fragment.
-Corrected drag handle icon.
-Removed reorder icon.
-Refactored play queue item selection.
2017-10-30 20:58:45 -07:00
John Zhen M
0d3e0c201e -Fixed MediaSourceManager from inserting already inserted entry. 2017-10-30 20:58:45 -07:00
John Zhen M
cc4e4a4f91 -Fixed external popup share not starting. 2017-10-30 20:58:45 -07:00
John Zhen M
b597774bb9 -Enabled play queue control in main video player.
-Fixed video players does not resolve to preferred quality on playlists.
-Refactored resolution conversion to Localization.
-Fixed video player quality menu building exception when stream info is not yet available.
2017-10-30 20:58:45 -07:00
John Zhen M
87fca5cffe -Enabled play queue control panel for popup video player.
-Refactored background player activity into generic play queue control panel activity.
-Changed control panel activities into singleTask.
2017-10-30 20:58:45 -07:00
John Zhen M
9685456ee4 -Added new intents to append streams to current player.
-Added long clicks for popup and background player buttons on details fragment for append intents.
-Removed restrictions for preventing UI to show up when player is buffering.
-Fixed icons for all repeat modes.
-Added Progress bar to background activity when player is in not ready state.
-Fixed Track Selection when switching between video and audio only on video players.
-Fixed video player to enable tunnelling only after sdk > 21.
-Fixed activity exception from restarting after service is shutdown on earlier sdk versions.
2017-10-30 20:58:45 -07:00
John Zhen M
6a9e3ef639 -Added dropdown menu for background player activity.
-Added icons for shuffle and drag handle.
-Fixed exception when returning to background player activity after service shuts down.
-Fixed open detail only working for Youtube.
2017-10-30 20:58:45 -07:00
John Zhen M
b5a9f042cc -Fixed background player activity crashes on receiving update when stopped (lifecycle still active). 2017-10-30 20:58:45 -07:00
John Zhen M
770dcc1832 -Fixed incorrect indexing due to item removed after shuffle.
-Fixed activity binding not unbound after service shutdown.
2017-10-30 20:58:45 -07:00
John Zhen M
94f7baf299 -Added variable speed and pitch to background player.
-Moved playback speed LUT to BasePlayer.
2017-10-30 20:58:44 -07:00
John Zhen M
77979eddde -Added shuffle button to background player.
-Extracted MediaSourceManager window size as parameter.
-Removed redundant list manipulation in PlayQueueAdapter.
2017-10-30 20:58:44 -07:00
John Zhen M
f1e52b8b92 -Fixed incorrect stream from being played after consecutive player errors.
-Fixed MediaSource reuse due to MediaSourceManager not resetting source on block.
2017-10-30 20:58:44 -07:00
John Zhen M
2e414cfd63 - Added move mechanic to background player through handles (on both thumbnail and icon).
- Added remove and open detail as long click popup dropdown on background player.
- Vastly simplified list manipulation in MediaSourceManager by delegating most control to DynamicConcatenatingMediaSource.
2017-10-30 20:58:44 -07:00
John Zhen M
f5b5982e1c -Improved DeferredMediaSource to build source on IO thread.
-Improved exception handling for player.
2017-10-30 20:58:44 -07:00
John Zhen M
eebd83d6ac -Fixed deferred media source from releasing reused resources.
-Fixed external play queue to load more than once.
-Fixed wrong item removal due to player error.
-Added new event to indicate error to play queue.
-Changed player error to skip item instead of removing.
-Modified play queue adapter to update changed items only.
-Removed headers from play queue adapter.
-Merged event broadcast on play queue.
-Changed toast on player error.
-Modified remove event to no longer indicate current index status.
-Modified move event to no longer indicate randomization status.
-Added shuffle check to play queue.
2017-10-30 20:58:44 -07:00
John Zhen M
a9aee21e58 - Improved play queue adapter for selection.
- Fixed media source resolution on background player for streams without an audio only stream.
- Fixed background player not updating when screen turns back on.
- Fixed background player notification switching to wrong repeat mode icon opacity on click.
2017-10-30 20:58:44 -07:00
John Zhen M
bd9ee18e56 -Fixed TransactionTooLarge due to notification being shown for too long.
-Fixed Play Queue rewinding to last played video upon removing the currently playing.
2017-10-30 20:58:44 -07:00
John Zhen M
c75c2d0f21 -Added documentations for play queue components. 2017-10-30 20:58:44 -07:00
John Zhen M
80f3e3c3b6 -Added temporary fix for mapping track selection with video streams.
-Updated ExoPlayer to 2.5.3.
2017-10-30 20:58:44 -07:00
John Zhen M
86a1fcf009 -Fixed unavailable current info when initial stream of playlist fails. 2017-10-30 20:58:43 -07:00
John Zhen M
c235c647a0 -Fixed background player notification update NPE. 2017-10-30 20:58:43 -07:00
John Zhen M
09d8ae1316 -Generify all player intents to use play queues.
-Fixed sync updates out-of-sync on background notification.
-Fixed main video player destroyed on resume.
-Fixed track selection using wrong dimension for parameter.
-Fixed background player to use default audio quality.
-Removed quality index from single queue items.
2017-10-30 20:58:43 -07:00
John Zhen M
cb7e94449c -Modified quality change to persist with its binding player.
-Fixed media source stops loading when the sequence of failed media is longer than window size.
-Changed player to release and reset on intent start.
-Removed update event.
2017-10-30 20:58:43 -07:00
John Zhen M
e742091a37 -Modified quality change to use internal track selection.
-Enabled audio processing integration with system EQ.
-Re-endabled HDR through tunneling on videos only.
2017-10-30 20:58:43 -07:00
John Zhen M
8e3be3826f -Fixed Deferred Media Source not working on non-extractor (e.g. dash) sources.
-Fixed NPE when extracting streams with no audio.
2017-10-30 20:58:43 -07:00
John Zhen M
9bc95f030c -Baked stream info resolution into custom media source, allowing for simpler playlist control.
-Added track merging on different stream qualities, allowing for implementation of smooth transition on A/V quality and captions change.
2017-10-30 20:58:43 -07:00
John Zhen M
9576d5bd89 -Fixed audio focus not working with timeline changes.
-Changed circular loading to boundary loading.
2017-10-30 20:58:43 -07:00
John Zhen M
a0ba3ce2e4 -Made playback manager load circular.
-Improved play previous button to reset before 5 seconds.
2017-10-30 20:58:43 -07:00
John Zhen M
6b816a11f7 -Added reorder event.
-Improved player blocking.
2017-10-30 20:58:43 -07:00
John Zhen M
86c7b8522e -Reverted current item removal and update logic.
-Updated external play queue.
2017-10-30 20:58:43 -07:00
John Zhen M
f9eb2a1ee5 -Fixed activity pause and resume lifecycle. 2017-10-30 20:58:43 -07:00
John Zhen M
174d040ca3 -Modified quality update to no longer invalidate concatenated media sources.
-Improved play queue and timeline update.
2017-10-30 20:58:42 -07:00
John Zhen M
6b16b08712 -Fixed bad window timeline caused by reusing media source on unblocking.
-Fixed timeline recovery skipping.
-Fixed timeline updates resumes playing when player is paused.
2017-10-30 20:58:42 -07:00
John Zhen M
e9cdb28a06 -Fixed audio focus change not firing. 2017-10-30 20:58:42 -07:00
John Zhen M
f8abf92a66 -Refactored Playback manager to expose only readonly methods.
-Removed swap and move operations.
-Code clean up.
2017-10-30 20:58:42 -07:00
John Zhen M
9413856463 -Added back notification on popup player. 2017-10-30 20:58:42 -07:00
John Zhen M
c24d46cf0f -Fixed seek problems caused by dynamic timeline .
-Removed debouncing, players are now much more responsive.
-Removed some redundant methods.
2017-10-30 20:58:42 -07:00
John Zhen M
c38e4190f1 -Fix restart button not working 2017-10-30 20:58:42 -07:00
John Zhen M
53cec61cdf -Removed redundant track removal after playing.
-Reverted thumbnail loader to use ImageLoader.
2017-10-30 20:58:42 -07:00
John Zhen M
150c3b413a -Fixed memory leak due to permanent remote view bitmap references.
-Removed redundant code in popup player.
2017-10-30 20:58:42 -07:00
John Zhen M
eb15c04254 -Added debouncing to index change reactor.
-Fixed repeat mode on background notification.
2017-10-30 20:58:42 -07:00
John Zhen M
7d7a6f7ccc -Enable background and popup playlists. 2017-10-30 20:58:42 -07:00
John Zhen M
b54d18d888 -Changed intents to start all players, including player swap.
-Make play queue and items serializable
-Removed now deprecated code for playing url in exoplayer
2017-10-30 20:58:42 -07:00
John Zhen M
705028c79d -Modified player repeat mode to use exoplayer repeat mode.
-Merged playback manager init load logic with normal load logic.
2017-10-30 20:58:41 -07:00
John Zhen M
a91ef2ce9e -Fix play queue remove.
-Fix player discontinuity refresh.
2017-10-30 20:58:41 -07:00
John Zhen M
73f46d3762 -Modified play queues and items to use extraction helper.
-Fixed play queue item removal.
-Rebase changes.
2017-10-30 20:58:41 -07:00
John Zhen M
1ceda017c7 -Revert subscription fragment merge fault 2017-10-30 20:58:41 -07:00
John Zhen M
725cedab72 -Unregister extractor submodule 2017-10-30 20:58:41 -07:00
John Zhen M
40b60e8313 -Error processing for failed video during queued playback. 2017-10-30 20:58:41 -07:00
John Zhen M
5c01f04a07 -Functional playlist using full play queue buffering. 2017-10-30 20:58:41 -07:00
John Zhen M
183181ee54 -Added full play queue buffering playback manager. 2017-10-30 20:58:41 -07:00
John Zhen M
74b58cae59 -Improved play queue message bus
-Hooking play queue engines with video players (to be removed)
-Proof of concept for previous and next controls
2017-10-30 20:58:41 -07:00
John Zhen M
b859823011 -Hooking playback manager and play queue into main video player. 2017-10-30 20:58:41 -07:00
John Zhen M
701320b100 -Added separate events for play queue index removal. 2017-10-30 20:58:40 -07:00
John Zhen M
dcdcf17f5e -Added on change event bus to Play Queue.
-Added playback manager for player interaction.
2017-10-30 20:58:40 -07:00
John Zhen M
7c9c3de644 -Rename playlist in players to play queue. 2017-10-30 20:58:40 -07:00
John Zhen M
cbcd281784 -Added MediaSourceManager and Playlist adapters. 2017-10-30 20:58:40 -07:00
John Zhen M
e70dcdc642 -Added rudimentary playlist fragment.
-Added schema for stream storage.
2017-10-30 20:58:40 -07:00
Christian Schabesberger
391d3e7fc7 fix back button for feed on main page 2017-10-30 23:03:18 +01:00
Christian Schabesberger
02d986fc89 fix multidefined swipe problem in history page 2017-10-30 22:46:55 +01:00
Christian Schabesberger
65a6488e44 dont show search history in suggestion when disabled 2017-10-30 22:04:58 +01:00
Christian Schabesberger
cf703d5213 Merge branch 'patch-1' of https://github.com/SpajicM/NewPipe into chron 2017-10-30 21:40:19 +01:00
Weblate
3a8437c6f3 Merge remote-tracking branch 'origin/dev' into dev 2017-10-30 19:45:58 +01:00
Joona Mattila
640396da64 Translated using Weblate (Finnish)
Currently translated at 100.0% (219 of 219 strings)
2017-10-30 19:45:55 +01:00
SpajicM
7e005549fe Fix history showing even when disabled 2017-10-30 11:53:44 +01:00
Christian Schabesberger
59b3362715 put bountysource bounty lable on top of readme 2017-10-29 21:34:52 +01:00
Weblate
9dc8e47113 Merge remote-tracking branch 'origin/dev' into dev 2017-10-29 19:17:45 +01:00
Emanuele Petriglia
e958545230 Translated using Weblate (Italian)
Currently translated at 100.0% (220 of 220 strings)
2017-10-29 19:17:43 +01:00
Joona Mattila
76f3e170d5 Translated using Weblate (Finnish)
Currently translated at 100.0% (220 of 220 strings)
2017-10-29 19:17:40 +01:00
Christian Schabesberger
a5af49dafd fix weblate crash 2017-10-29 14:23:47 +01:00
Christian Schabesberger
736d9fe450 Merge branch 'license-dialog' of https://github.com/TobiGr/NewPipe into license 2017-10-29 10:28:52 +01:00
Emanuele Petriglia
bd7a520316 Translated using Weblate (Italian)
Currently translated at 100.0% (220 of 220 strings)
2017-10-28 21:36:16 +02:00
Freddy Morán Jr
7f5b5d6f03 Translated using Weblate (Spanish)
Currently translated at 99.5% (219 of 220 strings)
2017-10-28 01:49:13 +02:00
Christian Schabesberger
8d5a59e7d5 fix light theme for main page 2017-10-26 23:56:02 +02:00
Christian Schabesberger
989acce0a5 Merge branch 'popup_improvement' of https://github.com/karyogamy/NewPipe into size 2017-10-26 20:49:43 +02:00
Christian Schabesberger
641b4a806a Merge branch 'tabs' into dev 2017-10-26 20:46:05 +02:00
Christian Schabesberger
025a44b629 fix channel title for new tabs 2017-10-26 20:45:16 +02:00
Christian Schabesberger
dd64bf2af7 make title contain current tab 2017-10-26 15:16:35 +02:00
Filip Sebastian
d5b3f65076 Translated using Weblate (Romanian)
Currently translated at 100.0% (220 of 220 strings)
2017-10-26 14:53:31 +02:00
ButterflyOfFire
66de4cbead Translated using Weblate (French)
Currently translated at 98.1% (216 of 220 strings)
2017-10-26 14:53:26 +02:00
ButterflyOfFire
be3d6adf77 Translated using Weblate (Arabic)
Currently translated at 30.9% (68 of 220 strings)
2017-10-26 14:53:23 +02:00
Eduardo Caron
65e83e8fb6 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (220 of 220 strings)
2017-10-26 14:53:14 +02:00
Christian Schabesberger
7a2be6f12c Merge pull request #784 from TobiGr/fix-kiosk-typo
Fix kiosk typo
2017-10-26 14:16:12 +02:00
Tobias Groza
0d6662b558 Translated using Weblate (German)
Currently translated at 95.0% (209 of 220 strings)
2017-10-26 11:46:10 +02:00
TobiGr
0a2aa54508 fix typo 2017-10-26 09:23:43 +02:00
John Zhen Mo
f6353cfb47 -Added fling mechanic for popup player shutdown.
-Changed long click to fill screen for popup player.
-Added 2-finger resizing for popup player.
-Removed long click resize mechanic.
2017-10-25 22:00:58 -07:00
Anton Shestakov
fb71ba3b7c Translated using Weblate (Russian)
Currently translated at 98.1% (216 of 220 strings)
2017-10-26 06:48:31 +02:00
Filip Sebastian
ac6e086c26 Translated using Weblate (French)
Currently translated at 94.0% (207 of 220 strings)
2017-10-25 20:39:55 +02:00
Christian Schabesberger
4c4cfb49b4 make tabs contain icons instead of title 2017-10-25 16:09:26 +02:00
Christian Schabesberger
9a073713bb put tabs on top 2017-10-25 15:20:57 +02:00
Filip Sebastian
4db3bd3270 Translated using Weblate (Romanian)
Currently translated at 100.0% (220 of 220 strings)
2017-10-25 00:01:23 +02:00
Filip Sebastian
d5d9ed7200 Translated using Weblate (Romanian)
Currently translated at 100.0% (220 of 220 strings)
2017-10-25 00:00:28 +02:00
Weblate
0e409bb993 Merge remote-tracking branch 'origin/dev' into dev 2017-10-24 23:56:06 +02:00
Joona Mattila
89a8769399 Translated using Weblate (Finnish)
Currently translated at 99.0% (204 of 206 strings)
2017-10-24 23:56:04 +02:00
Filip Sebastian
fdfd94b9d0 Translated using Weblate (Romanian)
Currently translated at 100.0% (206 of 206 strings)
2017-10-24 23:55:54 +02:00
Christian Schabesberger
ba56aec353 Merge branch 'trending' into dev 2017-10-23 23:14:49 +02:00
Christian Schabesberger
3ac3cedc19 add fdroid build server node to contribution.md 2017-10-23 15:16:34 +02:00
Christian Schabesberger
2756db6601 downgrade gralde wrapper to 4.2 2017-10-23 14:59:30 +02:00
Christian Schabesberger
7d296ee650 remove hardcoded strings form MainFragment 2017-10-23 00:26:20 +02:00
Christian Schabesberger
ccd26b4146 fix kiosk service/icon 2017-10-22 23:56:39 +02:00
Christian Schabesberger
5d4269be4c Merge branch 'dev' into trending 2017-10-22 23:43:48 +02:00
Christian Schabesberger
54cdfc0c16 deactivate icon 2017-10-22 22:53:27 +02:00
Christian Schabesberger
fd899a2e95 fix cammel case 2017-10-22 22:10:48 +02:00
Christian Schabesberger
d1f446aae2 make summary a dynamic string 2017-10-22 22:06:25 +02:00
Christian Schabesberger
c3f04ea67d fix Kisok spelling error 2017-10-22 21:46:50 +02:00
Coin
7b56aaad53 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 68.9% (142 of 206 strings)
2017-10-22 09:44:44 +02:00
Joona Mattila
b73677fa5e Translated using Weblate (Finnish)
Currently translated at 98.0% (202 of 206 strings)
2017-10-21 01:46:12 +02:00
TobiGr
0040ee5cb6 Fix charset issue.
Move Java I/O related methods to separate thread.
2017-10-20 23:41:30 +02:00
Weblate
f391574113 Merge remote-tracking branch 'origin/dev' into dev 2017-10-19 22:34:40 +02:00
Joona Mattila
ea863b0c24 Added translation using Weblate (Finnish) 2017-10-19 22:34:36 +02:00
Christian Schabesberger
4506c90e59 Merge pull request #771 from TeamNewPipe/master
Release v0.10.1
2017-10-18 11:59:53 +02:00
Christian Schabesberger
894a63ed82 Merge branch 'dev' into master 2017-10-18 11:56:11 +02:00
Christian Schabesberger
0155454526 moved on to version v0.10.1 2017-10-18 11:44:24 +02:00
Weblate
f7aafb87a8 Merge remote-tracking branch 'origin/dev' into dev 2017-10-17 14:51:16 +02:00
Anton Shestakov
227001ec32 Translated using Weblate (Russian)
Currently translated at 99.0% (204 of 206 strings)
2017-10-17 14:51:15 +02:00
Sérgio Marques
d765364915 Translated using Weblate (Portuguese)
Currently translated at 100.0% (206 of 206 strings)
2017-10-17 14:51:15 +02:00
developerchan1
3d47e63d6f Translated using Weblate (Indonesian)
Currently translated at 81.0% (167 of 206 strings)
2017-10-17 14:51:12 +02:00
Allan Nordhøy
79c5c3cc57 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.5% (205 of 206 strings)
2017-10-17 14:51:02 +02:00
Christian Schabesberger
8babbddcf9 Merge pull request #766 from jlelse/dev
Updated Gradle wrapper
2017-10-16 15:25:11 +02:00
Christian Schabesberger
13756508d3 Merge pull request #757 from coffeemakr/fix-service-id-not-initialized
Fix service id not initialized
2017-10-16 15:22:26 +02:00
Bruno Guerreiro
b7fe001b13 Translated using Weblate (Portuguese)
Currently translated at 100.0% (206 of 206 strings)
2017-10-15 19:10:11 +02:00
TheAssassin
35b4110a7a Fix half finished paragraph 2017-10-15 18:42:49 +02:00
Jan-Lk Else
cdca0c6325 Updated Gradle wrapper 2017-10-14 11:42:00 +02:00
Christian Schabesberger
d928f5759f try to fix margin / padding 2017-10-13 13:55:55 +02:00
Christian Schabesberger
23eeb4353d make main page changes display emediatly 2017-10-13 13:49:31 +02:00
Christian Schabesberger
8e8d74b5b7 remove header front kiosk 2017-10-13 13:01:16 +02:00
Weblate
094851cc7d Merge remote-tracking branch 'origin/dev' into dev 2017-10-13 02:33:58 +02:00
Enol P
f55612be40 Translated using Weblate (Asturian)
Currently translated at 100.0% (206 of 206 strings)
2017-10-13 02:33:51 +02:00
Christian Schabesberger
0951f0f824 small fixes
small fixes
2017-10-11 15:25:10 +02:00
Tryton Van Meer
b70fd826e7 Fix crash when returning to player.
When switching apps or locking the phone, destroyPlayer is called which sets audioManager to null. So upon returning to the player and pressing play, the app crashes.
So now initPlayer checks if audioManager is null and sets it if needed.
2017-10-11 14:27:32 +02:00
Coin
994559b39b Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (206 of 206 strings)
2017-10-10 18:06:26 +02:00
Christian Schabesberger
f7534b3a0f Merge branch 'dev' into trending 2017-10-09 14:37:20 +02:00
Christian Schabesberger
7fcc07805a make kiosk selector signle service again 2017-10-09 14:34:10 +02:00
Christian Schabesberger
7f9f075147 add selector for kiosk 2017-10-09 14:22:27 +02:00
Christian Schabesberger
cbfc359a99 add service icons 2017-10-09 12:22:01 +02:00
Nathan Follens
907842c672 Translated using Weblate (Dutch)
Currently translated at 100.0% (206 of 206 strings)
2017-10-09 11:50:02 +02:00
Cyril Müller
c890ab44d6 Merge branch 'dev' into fix-service-id-not-initialized 2017-10-09 11:23:19 +02:00
Coffeemakr
89b11ff71c Fail-fast for service id == -1 2017-10-08 22:11:38 +02:00
Tobias Groza
3e34eeeed7 Translated using Weblate (German)
Currently translated at 99.5% (205 of 206 strings)
2017-10-08 21:45:38 +02:00
Coffeemakr
69302fcbd0 Add icepicker proguard rules 2017-10-08 17:52:12 +02:00
Coffeemakr
60879351a9 Code improvement and logging 2017-10-08 17:52:07 +02:00
Matej U
f4433ac508 Translated using Weblate (Slovenian)
Currently translated at 100.0% (206 of 206 strings)
2017-10-07 21:12:32 +02:00
E T
7b7d0d6171 Translated using Weblate (Turkish)
Currently translated at 100.0% (206 of 206 strings)
2017-10-07 19:51:07 +02:00
Freddy Morán Jr
a6e0ed09a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (206 of 206 strings)
2017-10-07 19:16:42 +02:00
Emanuele Petriglia
19ed6ebbaf Translated using Weblate (Italian)
Currently translated at 100.0% (206 of 206 strings)
2017-10-07 14:21:02 +02:00
Andrea Troiano
dfeee17d39 Translated using Weblate (Italian)
Currently translated at 100.0% (206 of 206 strings)
2017-10-07 13:28:50 +02:00
Jonas
4c429c869c Translated using Weblate (French)
Currently translated at 100.0% (206 of 206 strings)
2017-10-06 12:15:39 +02:00
Christian Schabesberger
6d8a361c9a add menu to select kiosk of current service 2017-10-05 14:57:19 +02:00
Eduardo Caron
825de1b6ee Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (206 of 206 strings)
2017-10-05 13:19:37 +02:00
Weblate
124461f587 Merge remote-tracking branch 'origin/dev' into dev 2017-10-05 13:12:38 +02:00
CaptainCrumble
a570fa6110 Translated using Weblate (Portuguese)
Currently translated at 98.5% (202 of 205 strings)
2017-10-05 13:12:37 +02:00
CaptainCrumble
0e8df83bbd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (205 of 205 strings)
2017-10-05 13:11:14 +02:00
Christian Schabesberger
952c8428d8 Merge pull request #748 from mauriciocolli/improve-search
Improve search
2017-10-04 11:03:53 +02:00
Matej U
5fe2c10aa1 Translated using Weblate (Slovenian)
Currently translated at 100.0% (205 of 205 strings)
2017-10-02 21:11:57 +02:00
Andrea Troiano
1f4aa2506b Translated using Weblate (Italian)
Currently translated at 100.0% (205 of 205 strings)
2017-10-02 15:46:44 +02:00
Andrea Troiano
9f8844fa5f Translated using Weblate (Italian)
Currently translated at 100.0% (205 of 205 strings)
2017-10-01 15:31:58 +02:00
E T
990aa88e00 Translated using Weblate (Turkish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-30 09:19:13 +02:00
Nathan Follens
9e335c1894 Translated using Weblate (Dutch)
Currently translated at 100.0% (205 of 205 strings)
2017-09-29 23:27:32 +02:00
Jonas
8f2b9a6bb7 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)
2017-09-29 18:41:33 +02:00
Anton Shestakov
448f3e8918 Translated using Weblate (Russian)
Currently translated at 98.5% (202 of 205 strings)
2017-09-29 12:47:49 +02:00
Mladen Pejaković
62b2ab7571 Translated using Weblate (Serbian)
Currently translated at 100.0% (205 of 205 strings)
2017-09-29 11:27:25 +02:00
Christian Schabesberger
46fa9a9366 translate kiosk name using resources
fix CDATA fuu
2017-09-28 16:38:44 +02:00
Christian Schabesberger
29fee28d1d fix channel selection 2017-09-28 15:36:15 +02:00
Mauricio Colli
78cbfa20d9 Improve search
- Use a list instead of a popup
- Show search history entries
2017-09-28 10:06:48 -03:00
Freddy Morán Jr
ccd42d42ab Translated using Weblate (Spanish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-27 18:47:50 +02:00
Tobias Groza
abe03ef9a3 Translated using Weblate (German)
Currently translated at 99.5% (204 of 205 strings)
2017-09-27 18:45:48 +02:00
Anton Shestakov
9813ffb83b Translated using Weblate (Russian)
Currently translated at 97.5% (200 of 205 strings)
2017-09-27 15:47:52 +02:00
Mikas
b4eefa3eed Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (205 of 205 strings)
2017-09-26 18:52:53 +02:00
Christian Schabesberger
3490273b49 made fragments frontpagable 2017-09-26 18:16:39 +02:00
Christian Schabesberger
65c8b6e66a add selection for front page 2017-09-26 17:29:38 +02:00
Anton Shestakov
6a166b798a Translated using Weblate (Russian)
Currently translated at 97.5% (200 of 205 strings)

(cherry picked from commit efa262480a)
2017-09-26 09:04:38 -03:00
Jona Abdinghoff
0686aec606 Translated using Weblate (German)
Currently translated at 99.5% (204 of 205 strings)

(cherry picked from commit 2c8dd9ce2a)
2017-09-26 09:04:38 -03:00
Mikas
54b3c62803 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 4a4b1e0e49)
2017-09-26 09:04:38 -03:00
nailyk
40d83ba7e7 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit cb5e37184a)
2017-09-26 09:04:38 -03:00
trmdi
ea3c379d88 Translated using Weblate (Vietnamese)
Currently translated at 68.2% (140 of 205 strings)

(cherry picked from commit 094a3af8ae)
2017-09-26 09:04:38 -03:00
Yann Hodiesne
a6ee3e99ea Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 283d33aa27)
2017-09-26 09:04:38 -03:00
nailyk
b2cab4aea0 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 6c445c0833)
2017-09-26 09:04:38 -03:00
Krysa Czech
2a2e532acc Translated using Weblate (Czech)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit dd10c1756f)
2017-09-26 09:04:38 -03:00
pawelkw
0954a494e7 Translated using Weblate (Polish)
Currently translated at 80.9% (166 of 205 strings)

(cherry picked from commit 5ecad47d6e)
2017-09-26 09:04:38 -03:00
Krysa Czech
bc32c946ff Translated using Weblate (Czech)
Currently translated at 76.0% (156 of 205 strings)

(cherry picked from commit edfdabb691)
2017-09-26 09:04:38 -03:00
Ivan Krušlin
95debf66e5 Translated using Weblate (Croatian)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 4653e94c57)
2017-09-26 09:04:38 -03:00
Bruno Tendler
3b166f82a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 54df50f84d)
2017-09-26 09:04:38 -03:00
Ivan Krušlin
7d19250565 Translated using Weblate (Croatian)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit 6341ad88e8)
2017-09-26 09:04:38 -03:00
E T
c510a4149d Translated using Weblate (Turkish)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit f893edeb82)
2017-09-26 09:04:38 -03:00
E T
33e473c509 Translated using Weblate (Turkish)
Currently translated at 100.0% (205 of 205 strings)

(cherry picked from commit c1fe03aab6)
2017-09-26 09:04:38 -03:00
Christian Schabesberger
e3dfdb0b06 Merge pull request #738 from comradekingu/patch-4
Spelling: View → Play
2017-09-26 14:01:23 +02:00
Anton Shestakov
efa262480a Translated using Weblate (Russian)
Currently translated at 97.5% (200 of 205 strings)
2017-09-26 13:32:59 +02:00
Jona Abdinghoff
2c8dd9ce2a Translated using Weblate (German)
Currently translated at 99.5% (204 of 205 strings)
2017-09-26 09:46:23 +02:00
Allan Nordhøy
ead1399e7b Spelling: View → Play 2017-09-25 16:12:47 +02:00
Christian Schabesberger
5ebde97352 fix error report and add setting for current_service 2017-09-25 13:05:54 +02:00
Christian Schabesberger
f6c624b59a make name translatable, fix tab on items, remove back button
s/kisok/kiosk/g
2017-09-25 12:52:13 +02:00
Mikas
4a4b1e0e49 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (205 of 205 strings)
2017-09-25 00:47:09 +02:00
nailyk
cb5e37184a Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)
2017-09-23 21:45:34 +02:00
Fablab user
4b78a9366d s/TEAMPLATE/TEMPLATE/g
remove old teamplate
2017-09-23 21:17:08 +02:00
Christian Schabesberger
90b9223aae Merge branch 'dev' into trending 2017-09-23 20:39:01 +02:00
trmdi
094a3af8ae Translated using Weblate (Vietnamese)
Currently translated at 68.2% (140 of 205 strings)
2017-09-23 18:49:19 +02:00
Christian Schabesberger
0d2296917a creating first prototype of kiosk page 2017-09-23 17:39:04 +02:00
Coffeemakr
d6fffc7e55 Use correct long comparison (fixes #726) 2017-09-23 08:35:06 -03:00
Yann Hodiesne
283d33aa27 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)
2017-09-22 19:31:22 +02:00
nailyk
6c445c0833 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)
2017-09-22 19:30:28 +02:00
Krysa Czech
dd10c1756f Translated using Weblate (Czech)
Currently translated at 100.0% (205 of 205 strings)
2017-09-22 19:04:04 +02:00
TobiGr
74bda719a6 add themes to license dialog 2017-09-22 11:07:17 +02:00
Adrian Campos
ced75a9b60 Added Adaptive launcher Icon 2017-09-21 22:46:36 -03:00
pawelkw
5ecad47d6e Translated using Weblate (Polish)
Currently translated at 80.9% (166 of 205 strings)
2017-09-21 21:47:16 +02:00
Christian Schabesberger
6e11ca1ac4 Merge pull request #722 from TeamNewPipe/beta
add everything for beta release
2017-09-21 10:08:11 +02:00
Krysa Czech
edfdabb691 Translated using Weblate (Czech)
Currently translated at 76.0% (156 of 205 strings)
2017-09-21 00:45:00 +02:00
Ivan Krušlin
4653e94c57 Translated using Weblate (Croatian)
Currently translated at 100.0% (205 of 205 strings)
2017-09-21 00:44:47 +02:00
Bruno Tendler
54df50f84d Translated using Weblate (Spanish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-20 21:49:00 +02:00
Christian Schabesberger
7588c8de5a Update screenshots 2017-09-19 20:50:01 -03:00
Christian Schabesberger
d564199e88 add sigle issue signle thread rule 2017-09-19 20:41:45 -03:00
TobiGr
e458adb342 Update README.md
- add Bountysource to donate section
- add navigation
- add Github badges
2017-09-19 20:40:51 -03:00
John Carlson
b43a7354cf Use google() in buildscript 2017-09-19 20:40:31 -03:00
Ivan Krušlin
6341ad88e8 Translated using Weblate (Croatian)
Currently translated at 100.0% (205 of 205 strings)
2017-09-19 20:00:50 +02:00
Allan Nordhøy
314b2fb14f Spelling of file formats (#703) 2017-09-19 18:38:27 +02:00
Tobias Groza
795ba89dc4 Support dark theme in file picker (#699) 2017-09-19 18:38:27 +02:00
Felix Ableitner
5b8ff28556 Open youtube links directly from search (fixes #35) (#692)
* Open youtube links directly from search (fixes #35)
2017-09-19 18:38:27 +02:00
Christian Schabesberger
5e66a66111 enable minify 2017-09-19 18:38:27 +02:00
Mauricio Colli
3e6bed538a Update extractor version 2017-09-19 18:38:27 +02:00
E T
f893edeb82 Translated using Weblate (Turkish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-18 01:11:35 +02:00
Weblate
64e4adef29 Merge remote-tracking branch 'origin/master' 2017-09-16 10:36:43 +02:00
E T
c1fe03aab6 Translated using Weblate (Turkish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-16 10:36:32 +02:00
wb9688
25db3c2940 Update NewPipeExtractor 2017-09-16 10:25:54 +02:00
wb9688
442290d7f0 Hide spinner 2017-09-14 11:43:30 +02:00
wb9688
a6eb871f5e Change layout for audio-only streams 2017-09-14 10:49:39 +02:00
wb9688
b500c3f526 Add service setting 2017-09-14 09:31:01 +02:00
Christian Schabesberger
4b0a071a35 Merge pull request #691 from TeamNewPipe/minify
enable minify
2017-09-13 21:07:55 +02:00
Christian Schabesberger
4ef69969a7 enable minify 2017-09-12 13:32:53 +02:00
Weblate
c5885d9ce4 Merge remote-tracking branch 'origin/master' 2017-09-11 23:15:20 +02:00
Allan Nordhøy
4c2d705311 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (205 of 205 strings)
2017-09-11 23:15:16 +02:00
Mauricio Colli
939017ada9 Update extractor version 2017-09-11 11:21:01 -03:00
Matej U
322c5c05cf Translated using Weblate (Slovenian)
Currently translated at 100.0% (205 of 205 strings)
2017-09-11 11:29:26 +02:00
Jonas
cd174b8ce9 Translated using Weblate (French)
Currently translated at 100.0% (205 of 205 strings)
2017-09-11 10:12:00 +02:00
Oscar Hemelaar
f5999f28e9 Translated using Weblate (French)
Currently translated at 97.0% (199 of 205 strings)
2017-09-11 10:06:02 +02:00
Jonas
428a754bfc Translated using Weblate (French)
Currently translated at 96.5% (198 of 205 strings)
2017-09-11 10:05:38 +02:00
Weblate
9ba2a9d907 Merge remote-tracking branch 'origin/master' 2017-09-09 22:34:46 +02:00
Eduardo Caron
71a22348c9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (205 of 205 strings)
2017-09-09 22:34:45 +02:00
Tobias Groza
4ac0db1869 Translated using Weblate (French)
Currently translated at 80.9% (166 of 205 strings)
2017-09-09 22:34:36 +02:00
Nathan Follens
bca9035302 Translated using Weblate (Dutch)
Currently translated at 100.0% (205 of 205 strings)
2017-09-09 22:34:25 +02:00
Christian Schabesberger
33b316d72f update extractor to not throw channelextractor exception 2017-09-09 22:22:27 +02:00
Christian Schabesberger
020322df0b add everything for beta release
add AndroidManifest.xml for beta
2017-09-09 20:46:58 +02:00
Christian Schabesberger
6068043fd4 Fix pullrequest teamplate markdown issue 2017-09-09 19:04:30 +02:00
Weblate
2bf4032a6f Merge remote-tracking branch 'origin/master' 2017-09-09 00:46:59 +02:00
Enrico Monese
5e659e3f46 Translated using Weblate (Italian)
Currently translated at 97.0% (199 of 205 strings)
2017-09-09 00:46:56 +02:00
Mauricio Colli
23f70d6b8b Update extractor 2017-09-08 11:34:02 -03:00
Osoitz
ddcf2c5206 Translated using Weblate (Basque)
Currently translated at 100.0% (205 of 205 strings)
2017-09-08 15:44:27 +02:00
Tobias Groza
6b88349c77 Translated using Weblate (German)
Currently translated at 98.0% (201 of 205 strings)
2017-09-07 18:46:03 +02:00
Marian Hanzel
4eb2d3805d Translated using Weblate (Slovak)
Currently translated at 84.8% (174 of 205 strings)
2017-09-06 00:48:04 +02:00
Gaman Gabriel
6cdddc4e9f Translated using Weblate (Romanian)
Currently translated at 77.5% (159 of 205 strings)
2017-09-05 18:48:21 +02:00
Freddy Morán Jr
406d844722 Translated using Weblate (Spanish)
Currently translated at 100.0% (205 of 205 strings)
2017-09-05 14:47:09 +02:00
Mladen Pejaković
09ee0357c7 Translated using Weblate (Serbian)
Currently translated at 100.0% (205 of 205 strings)
2017-09-04 16:23:20 +02:00
Mauricio Colli
f603f63361 Another fix for Weblate 2017-09-04 09:31:53 -03:00
Mauricio Colli
720bb5d615 Fix strings for Weblate 2017-09-04 09:26:00 -03:00
Mauricio Colli
eebd76661d Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.5% (203 of 206 strings)
2017-09-04 14:10:52 +02:00
Mauricio Colli
7885ae5d3f Merge pull request #669 from mauriciocolli/refactor-newpipe
Update extractor and refactored NewPipe
2017-09-04 08:50:21 -03:00
Christian Schabesberger
08257cc5dd Merge pull request #671 from TobiGr/readme-typos
Fix typos in README
2017-09-04 01:39:23 +02:00
TobiGr
27f8144bb8 fix typos in README 2017-09-04 00:39:33 +02:00
Mauricio Colli
146d4a8365 Update extractor and refactored NewPipe 2017-09-03 13:57:12 -03:00
Walter White
bddd9b3409 Translated using Weblate (French)
Currently translated at 83.6% (164 of 196 strings)
2017-09-03 06:04:15 +02:00
Mauricio Colli
0d4d83f3a6 Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)
2017-09-03 06:04:14 +02:00
Anton Shestakov
4bb0bb4ff0 Translated using Weblate (Russian)
Currently translated at 97.9% (192 of 196 strings)
2017-09-02 18:48:04 +02:00
Mauricio Colli
2d75968532 Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)
2017-09-02 00:45:25 +02:00
Nathan Follens
aa0e759168 Translated using Weblate (Dutch)
Currently translated at 100.0% (196 of 196 strings)
2017-09-01 23:47:19 +02:00
Eduardo Caron
cdae745c00 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (196 of 196 strings)
2017-09-01 22:54:42 +02:00
Freddy Morán Jr
a8b6af1f03 Translated using Weblate (Spanish)
Currently translated at 100.0% (196 of 196 strings)
2017-09-01 06:58:52 +02:00
Mauricio Colli
c7106073b4 Translated using Weblate (German)
Currently translated at 90.8% (178 of 196 strings)
2017-09-01 00:17:13 +02:00
Mauricio Colli
d96139798f Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)
2017-09-01 00:17:13 +02:00
nautilusx
bd560644fe Translated using Weblate (German)
Currently translated at 97.9% (192 of 196 strings)
2017-08-31 22:09:52 +02:00
Tobias Groza
f6772c4138 Translated using Weblate (German)
Currently translated at 88.7% (174 of 196 strings)
2017-08-31 12:51:23 +02:00
Mauricio Colli
dd733640e5 Translated using Weblate (Portuguese (Brazil))
Currently translated at 86.7% (170 of 196 strings)
2017-08-31 05:20:12 +02:00
Allan Nordhøy
75a0c0a527 Translated using Weblate (Norwegian Bokmål)
Currently translated at 78.0% (153 of 196 strings)
2017-08-31 05:20:12 +02:00
Mauricio Colli
a5925875a7 Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)
2017-08-31 05:20:02 +02:00
Allan Nordhøy
84157f9247 Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)

Note that "Billion" is often "Milliard" in other languages.
2017-08-31 05:17:26 +02:00
Allan Nordhøy
fcf3ed7881 Translated using Weblate (English)
Currently translated at 100.0% (196 of 196 strings)
2017-08-31 03:45:01 +02:00
theVikac
dac3be69d6 Translated using Weblate (Croatian)
Currently translated at 100.0% (196 of 196 strings)
2017-08-30 09:15:40 +02:00
haseoxth
5118e5cceb Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (196 of 196 strings)
2017-08-30 08:15:06 +02:00
Janusz May
7ca0d20dda Translated using Weblate (Polish)
Currently translated at 98.9% (194 of 196 strings)
2017-08-29 15:47:28 +02:00
Marian Hanzel
378222e484 Translated using Weblate (Slovak)
Currently translated at 100.0% (196 of 196 strings)
2017-08-29 08:41:45 +02:00
mueller-ma
812bec205c Translated using Weblate (German)
Currently translated at 98.4% (193 of 196 strings)
2017-08-28 12:46:04 +02:00
Matej U
2ee8803e33 Translated using Weblate (Slovenian)
Currently translated at 100.0% (196 of 196 strings)
2017-08-27 12:48:39 +02:00
wb9688
007616ca42 Translated using Weblate (Dutch)
Currently translated at 100.0% (196 of 196 strings)
2017-08-27 09:45:09 +02:00
Osoitz
f3b235e4a7 Translated using Weblate (Basque)
Currently translated at 95.9% (188 of 196 strings)
2017-08-26 15:44:19 +02:00
anonymous
074d4be4ba Translated using Weblate (Dutch)
Currently translated at 100.0% (196 of 196 strings)
2017-08-26 09:34:35 +02:00
wb9688
03cd48257b Translated using Weblate (Dutch)
Currently translated at 100.0% (196 of 196 strings)
2017-08-26 09:33:21 +02:00
zmni
546db83de3 Translated using Weblate (Indonesian)
Currently translated at 95.4% (187 of 196 strings)
2017-08-25 18:46:09 +02:00
Matej U
cc11a39f7e Translated using Weblate (Slovenian)
Currently translated at 99.4% (195 of 196 strings)
2017-08-24 00:48:01 +02:00
Eduardo Caron
a83b365afd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (196 of 196 strings)
2017-08-23 15:22:27 +02:00
Freddy Morán Jr
6a6cfac603 Translated using Weblate (Spanish)
Currently translated at 100.0% (196 of 196 strings)
2017-08-22 01:27:56 +02:00
Weblate
5270cedc56 Merge remote-tracking branch 'origin/master' 2017-08-20 21:45:05 +02:00
Michalis Nikolaidis
2ac833d2a6 Translated using Weblate (Greek)
Currently translated at 22.6% (44 of 194 strings)
2017-08-20 21:45:04 +02:00
Blader
f7be210b12 Translated using Weblate (Dutch)
Currently translated at 93.2% (181 of 194 strings)
2017-08-20 21:44:58 +02:00
Christian Schabesberger
24774d7921 Merge pull request #656 from karyogamy/exoplayer_update
Updated ExoPlayer to r2.5.1
2017-08-18 22:05:31 +02:00
John Zhen M
2b2e954b84 -Updated ExoPlayer to r2.5.1.
-Fixes some more deprecations due to Exoplayer and Android O notification updates.
2017-08-18 11:07:57 -07:00
Tonelico
85108be686 Android O Notification Building Fix (#655)
-Added simple notification channel for Android O.
-Fixes notification building failure for background and popup player on Android O.
-Reduce notification channel importance to low to avoid making noise on every notification update.
2017-08-18 09:05:31 -03:00
Oscar Hemelaar
9fbac943bb Translated using Weblate (French)
Currently translated at 98.4% (191 of 194 strings)
2017-08-18 00:45:31 +02:00
theVikac
d901eaa8d2 Translated using Weblate (Croatian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-17 12:44:50 +02:00
mueller-ma
5fb0e8d007 Translated using Weblate (German)
Currently translated at 98.4% (191 of 194 strings)

In german there is no 's
2017-08-16 21:45:40 +02:00
theVikac
cd5c76cb76 Translated using Weblate (Croatian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-16 10:56:32 +02:00
theVikac
b2a64f8bf3 Added translation using Weblate (Croatian) 2017-08-16 10:50:18 +02:00
mueller-ma
b91acc9de5 Translated using Weblate (German)
Currently translated at 96.9% (188 of 194 strings)
2017-08-15 19:40:37 +02:00
Weblate
07836c7ffa Merge remote-tracking branch 'origin/master' 2017-08-15 19:40:01 +02:00
Tobias Groza
8b30a0d7cc Translated using Weblate (German)
Currently translated at 96.9% (188 of 194 strings)
2017-08-15 19:39:58 +02:00
Mauricio Colli
13a3e2feb2 Merge pull request #654 from coffeemakr/feature-add-components
Add licenses for RxJava
2017-08-15 13:10:11 -03:00
Coffeemakr
f4dca71497 Add licenses for RxJava (and bindings) 2017-08-15 17:21:11 +02:00
Gian Maria Viglianti
e4c6e87338 Translated using Weblate (Italian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-14 18:46:46 +02:00
Eduardo Caron
b2862520fd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (194 of 194 strings)
2017-08-14 18:34:54 +02:00
Lucas Friederich
bb29f1ea95 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.3% (187 of 194 strings)
2017-08-14 18:32:58 +02:00
Freddy Morán Jr
69b92757f4 Translated using Weblate (Spanish)
Currently translated at 100.0% (194 of 194 strings)
2017-08-14 03:46:52 +02:00
Mladen Pejaković
62ae2652c7 Translated using Weblate (Serbian)
Currently translated at 95.3% (185 of 194 strings)
2017-08-14 00:46:35 +02:00
anonymous
6f6633050b Translated using Weblate (Italian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-13 17:22:20 +02:00
Gian Maria Viglianti
d37bfd6651 Translated using Weblate (Italian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-13 17:21:56 +02:00
anonymous
55a17a8a83 Translated using Weblate (Italian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-13 17:21:04 +02:00
Gian Maria Viglianti
422b06b72d Translated using Weblate (Italian)
Currently translated at 100.0% (194 of 194 strings)
2017-08-13 17:17:58 +02:00
Freddy Morán Jr
873a1d1c3b Translated using Weblate (Spanish)
Currently translated at 100.0% (194 of 194 strings)
2017-08-13 03:06:27 +02:00
Weblate
44d06767b5 Merge remote-tracking branch 'origin/master' 2017-08-12 18:45:10 +02:00
Thomas Lavend'Homme
3f4379afbf Translated using Weblate (French)
Currently translated at 98.9% (181 of 183 strings)
2017-08-12 18:45:06 +02:00
Cyril Müller
c0515de6b7 Add search and watch history (#626)
Add search and watch history

* Make MainActicity a single task
* Remove some casting
* SearchFragment: start searching when created with query
* Handle settings change in onResume
* History: Log pop up and background playback
* History: Add swipe to remove functionallity
* Enable history by default
* Use stream item
* Store more information about the stream
* Integrate history database into AppDatabase
* Remove redundant casts
* Re-enable date converters
* History: Use Rx Java and run DB in background
 * Also make HistoryDAO extend BasicDAO
* History: RX-ify swipe to remove
* Sort history entries by creation date
* History: Set toolbar title
* Don't repeat history entries
  * Introduced setters so we can update entries in the database
  * If the latest entry has the same (main) values, just update it
2017-08-12 01:50:25 -03:00
anonymous
09159ec245 Translated using Weblate (French)
Currently translated at 93.9% (172 of 183 strings)
2017-08-11 17:05:11 +02:00
Thomas Lavend'Homme
ab0bf80888 Translated using Weblate (French)
Currently translated at 93.4% (171 of 183 strings)
2017-08-11 17:04:40 +02:00
anonymous
74b8eaed04 Translated using Weblate (French)
Currently translated at 86.3% (158 of 183 strings)
2017-08-11 16:05:34 +02:00
anonymous
d64b5ccae2 Translated using Weblate (French)
Currently translated at 85.7% (157 of 183 strings)
2017-08-11 15:58:59 +02:00
anonymous
3883212ca7 Translated using Weblate (French)
Currently translated at 85.2% (156 of 183 strings)
2017-08-11 15:56:20 +02:00
anonymous
1cec41dba0 Translated using Weblate (French)
Currently translated at 84.6% (155 of 183 strings)
2017-08-11 15:56:01 +02:00
anonymous
d00c0ff60c Translated using Weblate (French)
Currently translated at 84.1% (154 of 183 strings)
2017-08-11 15:55:42 +02:00
anonymous
1d597c5f5b Translated using Weblate (French)
Currently translated at 83.6% (153 of 183 strings)
2017-08-11 15:54:41 +02:00
anonymous
c004ef7d0b Translated using Weblate (French)
Currently translated at 83.0% (152 of 183 strings)
2017-08-11 15:54:22 +02:00
Freddy Morán Jr
1bfb977b28 Translated using Weblate (Spanish)
Currently translated at 100.0% (183 of 183 strings)
2017-08-10 19:18:55 +02:00
Osoitz
04138047f6 Translated using Weblate (Basque)
Currently translated at 100.0% (183 of 183 strings)
2017-08-10 14:03:01 +02:00
zmni
147e99a915 Translated using Weblate (Indonesian)
Currently translated at 97.2% (178 of 183 strings)
2017-08-09 15:45:45 +02:00
Matej U
6f7d162edc Translated using Weblate (Slovenian)
Currently translated at 97.8% (179 of 183 strings)
2017-08-09 12:46:52 +02:00
Weblate
910aee4b73 Merge remote-tracking branch 'origin/master' 2017-08-07 20:03:29 +02:00
mueller-ma
77e376751a Translated using Weblate (German)
Currently translated at 96.7% (177 of 183 strings)
2017-08-07 20:03:28 +02:00
Eduardo Caron
7e1264ac44 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (183 of 183 strings)
2017-08-07 20:03:26 +02:00
Christian Schabesberger
8f3a4a5a04 moved on to version v0.10.0 2017-08-07 18:16:19 +02:00
anonymous
2d2689362d Translated using Weblate (German)
Currently translated at 93.9% (172 of 183 strings)
2017-08-07 17:52:56 +02:00
Coffeemaker
913500a6de Translated using Weblate (German)
Currently translated at 93.9% (172 of 183 strings)
2017-08-07 17:51:43 +02:00
Weblate
81d7c54a55 Merge remote-tracking branch 'origin/master' 2017-08-07 17:50:22 +02:00
mueller-ma
4501d5a8fc Translated using Weblate (German)
Currently translated at 99.4% (172 of 173 strings)
2017-08-07 17:50:16 +02:00
Tonelico
becc90409f Added option to resume on audio focus regain. (#624) 2017-08-07 10:04:36 -03:00
Tonelico
10c4f7b465 Added basic channel subscription and feed pages (#620)
Added basic channel subscription and feed pages

- Room Persistence for sqlite support.
- RxJava2 for reactive async support.
- Stetho for database inspection support.
- Enabled Multidex for debug build.
2017-08-07 10:02:30 -03:00
Janusz May
cb5b0ff764 Translated using Weblate (Polish)
Currently translated at 98.8% (171 of 173 strings)
2017-08-04 18:46:15 +02:00
Wout B
277a817eaf Translated using Weblate (Dutch)
Currently translated at 100.0% (173 of 173 strings)
2017-08-04 17:07:20 +02:00
zmni
fbac6f6a57 Translated using Weblate (Indonesian)
Currently translated at 100.0% (173 of 173 strings)
2017-08-04 15:58:58 +02:00
monolifed
b1b0d6ceb6 Translated using Weblate (Turkish)
Currently translated at 100.0% (173 of 173 strings)
2017-08-03 21:38:20 +02:00
Eduardo Caron
07421542df Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (173 of 173 strings)
2017-08-03 14:19:56 +02:00
Weblate
74a8139ac9 Merge remote-tracking branch 'origin/master' 2017-08-03 14:16:37 +02:00
Osoitz
77eb76fefb Translated using Weblate (Basque)
Currently translated at 100.0% (167 of 167 strings)
2017-08-03 14:16:35 +02:00
Eduardo Caron
42a450c61f Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (167 of 167 strings)
2017-08-03 14:16:26 +02:00
TheAssassin
9e2ed10144 Fix bugs in CONTRIBUTING.md
Spelling and grammar bugs, a few additions here and there, make it sound like a team project instead of a one-man show.
2017-08-02 23:34:46 +02:00
Christian Schabesberger
27e5ce7f9b update sentry linkg 2017-08-02 23:19:34 +02:00
Mauricio Colli
f7b322da49 Fix audio focus bug 2017-08-02 14:14:45 -03:00
Mauricio Colli
16ad13c962 Update travis' android and build-tools version 2017-08-01 23:18:47 -03:00
Mauricio Colli
a8880bbc0a Merge pull request #642 from karyogamy/sdk_26_updrade
Upgrade target sdk and support library version to 26
2017-08-01 22:58:54 -03:00
Mauricio Colli
f020b88db3 Move maven repository declaration
- Remove redundant jcenter (already included in the "global application" build.gradle)
2017-08-01 22:56:04 -03:00
Mauricio Colli
a4f5c9e2a3 Merge pull request #636 from coffeemakr/feature-renaming-patterns
Add renaming filename preferences
2017-08-01 22:03:19 -03:00
Mauricio Colli
96d3841dba Fix issues #636 2017-08-01 21:56:51 -03:00
John Zhen M
39277d569f - Updated target, build tools and support libraries version to 26.
- Added dependency repositories jcenter and maven.google.com.
- Changed deprecated ActionBarActivity to AppCompatActivity.
2017-08-01 14:54:32 -07:00
Bruno Guerreiro
75b5bc03f7 Translated using Weblate (Portuguese)
Currently translated at 100.0% (167 of 167 strings)
2017-08-01 18:37:57 +02:00
Osoitz
01e17d9c2e Translated using Weblate (Basque)
Currently translated at 100.0% (167 of 167 strings)
2017-08-01 11:20:14 +02:00
Emilio Loi
8047ff96a8 Translated using Weblate (Italian)
Currently translated at 100.0% (167 of 167 strings)
2017-07-29 15:45:43 +02:00
Gian Maria Viglianti
0e737a2f3b Translated using Weblate (Italian)
Currently translated at 100.0% (167 of 167 strings)
2017-07-28 13:10:51 +02:00
Emilio Loi
854579d814 Translated using Weblate (Italian)
Currently translated at 100.0% (167 of 167 strings)
2017-07-28 13:10:42 +02:00
Emilio Loi
f3cbd99e45 Translated using Weblate (Italian)
Currently translated at 100.0% (167 of 167 strings)

"Cancellare" is "to clear" in writing context
2017-07-28 13:07:02 +02:00
Emilio Loi
c13ed3f347 Translated using Weblate (Italian)
Currently translated at 100.0% (167 of 167 strings)

There is enough space to more descriptive with this text
2017-07-28 13:05:33 +02:00
Emilio Loi
7409b58546 Translated using Weblate (Italian)
Currently translated at 99.4% (167 of 167 strings)
2017-07-28 13:00:17 +02:00
Emilio Loi
404ebb8810 Translated using Weblate (Italian)
Currently translated at 99.4% (166 of 167 strings)

I've inverted position of sentence "help is always welcome" from end to start, merging "The more is done the better it gets!" with the first part of the paragraph
2017-07-28 13:00:13 +02:00
Emilio Loi
b4a9a300c5 Translated using Weblate (Italian)
Currently translated at 97.6% (163 of 167 strings)
2017-07-28 12:58:37 +02:00
Fekrod
aa637e6a2b Translated using Weblate (Vietnamese)
Currently translated at 100.0% (167 of 167 strings)
2017-07-27 04:27:32 +02:00
Fekrod
85132e1e6e Added translation using Weblate (Vietnamese) 2017-07-27 02:59:08 +02:00
Eduardo Caron
f0aa5a4646 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (165 of 167 strings)
2017-07-26 15:46:21 +02:00
Coffeemakr
b0479d0bd9 Add renaming filename patterns 2017-07-24 13:01:24 +02:00
riotism
e475b888aa Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (167 of 167 strings)
2017-07-23 21:44:23 +02:00
Nigel
a8a3bbd9f5 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (167 of 167 strings)
2017-07-22 20:38:39 +02:00
riotism
f3cbd17598 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (167 of 167 strings)
2017-07-22 20:38:09 +02:00
riotism
3d7e4dc286 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (167 of 167 strings)
2017-07-22 20:35:53 +02:00
anonymous
2e98729527 Translated using Weblate (German)
Currently translated at 100.0% (167 of 167 strings)
2017-07-20 12:45:26 +02:00
Coffeemaker
3ac838a7ec Translated using Weblate (German)
Currently translated at 99.4% (167 of 167 strings)
2017-07-19 11:42:47 +02:00
Weblate
a1bd5bfc00 Merge remote-tracking branch 'origin/master' 2017-07-19 11:42:41 +02:00
Matej U
b99571a797 Translated using Weblate (Slovenian)
Currently translated at 98.8% (165 of 167 strings)
2017-07-19 11:42:41 +02:00
anonymous
43dec8914c Translated using Weblate (German)
Currently translated at 99.4% (166 of 167 strings)
2017-07-19 11:42:39 +02:00
Christian Schabesberger
5b5cb78595 Merge pull request #633 from coffeemakr/fix-time-links
Prevent "time links" from beeing clicked
2017-07-19 11:38:07 +02:00
Coffeemakr
cb8c919609 Prevent time links from beeing clicked 2017-07-19 10:26:26 +02:00
Anton Shestakov
be3810dfed Translated using Weblate (Russian)
Currently translated at 100.0% (167 of 167 strings)
2017-07-19 07:58:41 +02:00
Weblate
b961b59ad4 Merge remote-tracking branch 'origin/master' 2017-07-17 23:14:27 +02:00
Matej U
d2fbb86d8a Translated using Weblate (Slovenian)
Currently translated at 98.2% (164 of 167 strings)
2017-07-17 23:14:27 +02:00
Mauricio Colli
782c6211d0 Added translation using Weblate (Lithuanian) 2017-07-17 23:14:24 +02:00
Christian Schabesberger
c0dd11b61a move on to v0.9.10 2017-07-15 23:01:34 +02:00
Weblate
885830849e Merge remote-tracking branch 'origin/master' 2017-07-15 15:45:49 +02:00
Coffeemaker
079958f66b Translated using Weblate (German)
Currently translated at 97.6% (164 of 168 strings)
2017-07-15 15:45:48 +02:00
naofum
77c5d7d160 Translated using Weblate (Japanese)
Currently translated at 94.0% (158 of 168 strings)
2017-07-15 15:45:38 +02:00
Mauricio Colli
327195dcca Merge pull request #628 from coffeemakr/fix-make-github-url-untranslatable
Make github_url not translatable
2017-07-13 22:06:21 -03:00
Coffeemakr
cfbc88d375 Make github_url not translatable 2017-07-13 22:05:47 +02:00
Tobias Groza
d75a11b397 Translated using Weblate (German)
Currently translated at 94.6% (159 of 168 strings)
2017-07-13 22:02:54 +02:00
Freddy Morán Jr
8706da2890 Translated using Weblate (Spanish)
Currently translated at 100.0% (168 of 168 strings)
2017-07-13 20:25:43 +02:00
monolifed
824a06c39b Translated using Weblate (Turkish)
Currently translated at 100.0% (168 of 168 strings)
2017-07-12 19:52:00 +02:00
Nathan Follens
9c80c37ee9 Translated using Weblate (Dutch)
Currently translated at 100.0% (168 of 168 strings)
2017-07-12 18:51:06 +02:00
Weblate
ad6d383ee2 Merge remote-tracking branch 'origin/master' 2017-07-12 18:44:34 +02:00
Tobias Groza
5251f970b7 Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-07-12 18:44:33 +02:00
Coin
2225927bb1 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (151 of 151 strings)
2017-07-12 18:44:28 +02:00
Mauricio Colli
d210b600d7 Merge pull request #625 from coffeemakr/fix-nullpointer-in-background-handler
Check if view still exists in UICallback
2017-07-12 08:46:20 -03:00
Coffeemakr
70da5769d4 Check if view still exists in UICallback 2017-07-12 09:51:23 +02:00
Mauricio Colli
69e3814c77 Merge pull request #612 from coffeemakr/feature-about-activity
Add about activity
2017-07-11 12:49:14 -03:00
Coffeemakr
d950e11332 Small fixes for AboutActivity
* Remove parent activity
 * Finish activity on "up action"
 * Remove unused dimensions
2017-07-11 12:52:20 +02:00
Weblate
1a2b18f722 Merge remote-tracking branch 'origin/master' 2017-07-10 18:13:22 +02:00
George Netu
af78369f87 Translated using Weblate (Romanian)
Currently translated at 99.3% (150 of 151 strings)
2017-07-10 18:13:21 +02:00
Coin
8e4aca0582 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (151 of 151 strings)
2017-07-10 18:13:18 +02:00
Mauricio Colli
b603c178d1 Fix focus search fragment 2017-07-10 00:25:10 -03:00
Mauricio Colli
31e5a7afb0 Improve navigation/backstack 2017-07-10 00:14:24 -03:00
Mauricio Colli
6fb1847327 Update gradle wrapper version 2017-07-09 23:22:46 -03:00
Mauricio Colli
0c1d773134 Merge pull request #596 from marcobiscaro2112/master
Adds support for adjustable playback speed
2017-07-09 22:49:05 -03:00
Mauricio Colli
894ea27df2 Fix issues #596 2017-07-09 22:38:47 -03:00
Coffeemakr
f13731f91e Add about activity 2017-07-05 19:35:15 +02:00
Weblate
6742cbfd59 Merge remote-tracking branch 'origin/master' 2017-07-05 18:44:18 +02:00
Osoitz
6c0dea6138 Translated using Weblate (Basque)
Currently translated at 100.0% (151 of 151 strings)
2017-07-05 18:44:14 +02:00
Mauricio Colli
388e8d0c2f Merge pull request #607 from coffeemakr/fix-remove-bottom-margin-2
Fix margin at the bottom (v2)
2017-07-04 13:33:19 -03:00
Weblate
27b455592a Merge remote-tracking branch 'origin/master' 2017-07-03 16:36:40 +02:00
Osoitz
dad1c04528 Translated using Weblate (Basque)
Currently translated at 100.0% (151 of 151 strings)
2017-07-03 16:36:35 +02:00
Coffeemakr
4ad9fcdc6f Revert error/retry/loading changes 2017-07-02 22:22:37 +02:00
Christian Schabesberger
81b7fe0e9c Merge pull request #606 from edcaron/patch-1
fix f-droid repository link
2017-07-02 22:16:42 +02:00
Eduardo Caron
735cc8d6cc fix f-droid repository link 2017-07-02 16:14:22 -03:00
Christian Schabesberger
43a1c4ce11 move on to v0.9.9 2017-06-30 21:34:28 +02:00
Mauricio Colli
9ca048a881 Merge pull request #600 from coffeemakr/feature-code-improvements
Remove unused code
2017-06-29 17:51:33 -03:00
Coffeemakr
bab3dd417e Remove unused code
* Remove Giga crash handler
 * Some refactoring
 * Remove unused download dialog
 * Remove duplicated intent creation
2017-06-29 12:54:07 +02:00
Weblate
11541310d6 Merge remote-tracking branch 'origin/master' 2017-06-29 07:50:35 +02:00
Anton Shestakov
76740303c5 Translated using Weblate (Russian)
Currently translated at 100.0% (151 of 151 strings)
2017-06-29 07:50:32 +02:00
Mauricio Colli
0a7ecb89ce Adjust fragments' enter/exit animations
- Make a little bit faster
2017-06-28 16:38:13 -03:00
Mauricio Colli
c16a7d5da2 Merge pull request #599 from coffeemakr/feature-code-improvements
Code Improvements
2017-06-28 16:28:16 -03:00
Coffeemakr
b03723c3fb Code improvements
* Replace unchecked casts with checked casts
 * remove Utility.finViewById
 * Fix return activity checking
 * Create UserAction enum
 * Fix typos
 * Add instrumented test for error info
 * ErrorInfo make fields final
 * Log exception using logger
 * Add inherited annotations
 * Resolve deprecation warnings
 * Remove unused methods from utility
 * Reformat code
 * Remove unused methods from Utility and improve getFileExt
 * Create OnScrollBelowItemsListener
2017-06-28 18:56:05 +02:00
Mauricio Colli
40213b2d6a Fix autoplay
- Closes #595
2017-06-27 22:39:33 -03:00
Mauricio Colli
e8b71e867c Merge pull request #588 from coffeemakr/feature-speedup
Speed up detail page loading ⏱
2017-06-27 18:12:30 -03:00
Coffeemakr
8ab1b7fd8f Fix loading and retry positioning 2017-06-27 22:36:31 +02:00
Coffeemakr
8009aa975e Revert unused changes 2017-06-27 14:11:15 +02:00
Coffeemakr
cea706d14a Synchronize initRealtedVideoStreams* 2017-06-27 12:44:20 +02:00
Marco Biscaro
7b60648424 Adds support for adjustable playback speed
ExoPlayer was updated to 2.4.2, which supports playback speed change.

A speed selector was also added in the MainPlayer and PlayerPopup.

Fixes #153.
2017-06-26 19:22:16 -03:00
Eduardo Caron
3cb4952281 Translated using Weblate (Portuguese)
Currently translated at 93.3% (141 of 151 strings)
2017-06-26 21:46:21 +02:00
Coffeemakr
ec1ae647b0 Revert toolbar_search_clear 2017-06-26 14:19:42 +02:00
Coffeemakr
a3be9f36b3 Fix landscape stream item height 2017-06-26 12:42:35 +02:00
Weblate
451910763d Merge remote-tracking branch 'origin/master' 2017-06-19 12:46:26 +02:00
Coffeemaker
884dc38701 Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-19 12:46:26 +02:00
Anton Shestakov
3cca7aead9 Translated using Weblate (Russian)
Currently translated at 96.0% (145 of 151 strings)
2017-06-19 12:46:24 +02:00
Coffeemakr
4c4852129e Layout fixes
* Add selectableItemBackground to the player button
* Make uploader margin to padding
* Convert layout gravity center_horizontal to width=match_parent
2017-06-18 17:25:13 +02:00
Coffeemakr
ae2b0cc76b Format code and remove unused methods 2017-06-18 15:43:11 +02:00
Coffeemakr
71e963c853 Correct icons and title alignment 2017-06-17 14:19:55 +02:00
Coffeemakr
89b680f6d9 Revert RecyclerView to LinearLayout 2017-06-17 13:43:09 +02:00
Christian Schabesberger
f3eacac4ce Merge pull request #586 from coffeemakr/fix-spaces-in-folder
Fix download path handling (#580)
2017-06-16 18:05:05 +02:00
Anton Shestakov
26ec32cbe1 Translated using Weblate (Russian)
Currently translated at 95.3% (144 of 151 strings)
2017-06-16 15:46:23 +02:00
Coffeemakr
6d74038866 Improve speed
* Replace relative layouts and use Recycler view
 * Handle HTML in background
2017-06-16 14:02:45 +02:00
Kristoffer Grundström
7e45e88914 Translated using Weblate (Swedish)
Currently translated at 66.8% (101 of 151 strings)
2017-06-15 03:46:30 +02:00
Coffeemakr
62a4869eb7 Fix download path handling (#580) 2017-06-13 10:47:40 +02:00
Weblate
4f8b51701b Merge remote-tracking branch 'origin/master' 2017-06-13 00:53:12 +02:00
Kristoffer Grundström
169bcc2550 Added translation using Weblate (Swedish) 2017-06-13 00:53:09 +02:00
Christian Schabesberger
88b29cbbf9 moved on to v0.8.9 2017-06-11 14:16:43 +02:00
Christian Schabesberger
51d4d0d3dc Merge branch 'improve-backstack' of https://github.com/mauriciocolli/NewPipe into back 2017-06-11 14:08:47 +02:00
Christian Schabesberger
a482aa1e21 Merge branch 'master' of https://github.com/SpajicM/NewPipe into count 2017-06-11 14:03:49 +02:00
Christian Schabesberger
040b38689d update extractor to v0.9.8 2017-06-11 14:02:57 +02:00
Christian Schabesberger
8e8e53c4d5 update gradle 2017-06-11 13:54:44 +02:00
Marian Hanzel
d717c6d2f6 Translated using Weblate (Slovak)
Currently translated at 100.0% (151 of 151 strings)
2017-06-11 11:27:55 +02:00
Gian Maria Viglianti
9587ce97a8 Translated using Weblate (Italian)
Currently translated at 100.0% (151 of 151 strings)
2017-06-10 00:45:35 +02:00
Janusz May
aaaf573475 Translated using Weblate (Polish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-09 21:45:56 +02:00
zmni
6c6f322d90 Translated using Weblate (Indonesian)
Currently translated at 100.0% (151 of 151 strings)
2017-06-09 19:21:07 +02:00
Matej U
c03f0ed1fb Translated using Weblate (Slovenian)
Currently translated at 100.0% (151 of 151 strings)
2017-06-09 09:46:56 +02:00
Benedikt Freisen
55287393be Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-09 00:45:04 +02:00
Eduardo Caron
9575f92165 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (151 of 151 strings)
2017-06-09 00:24:10 +02:00
SpajicM
a5cbaad804 BackgroundPlayer: Add timestamp in expanded notification 2017-06-08 23:28:45 +02:00
monolifed
f492414b5e Translated using Weblate (Turkish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-08 18:46:54 +02:00
monolifed
3e6ddf7176 Translated using Weblate (English)
Currently translated at 100.0% (151 of 151 strings)
2017-06-08 18:44:44 +02:00
Gian Maria Viglianti
29ffb05653 Translated using Weblate (Italian)
Currently translated at 100.0% (151 of 151 strings)
2017-06-08 00:17:12 +02:00
Freddy Morán Jr
50c3ee2e9c Translated using Weblate (Spanish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-07 21:40:04 +02:00
Janusz May
6292470677 Translated using Weblate (Polish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-07 20:05:38 +02:00
Nathan Follens
8d912f2673 Translated using Weblate (Dutch)
Currently translated at 100.0% (151 of 151 strings)
2017-06-07 16:53:40 +02:00
Coffeemaker
227d129c3a Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 23:03:03 +02:00
Benedikt Freisen
d9eeb6afa0 Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 23:00:51 +02:00
anonymous
478aecb0f4 Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 23:00:14 +02:00
Benedikt Freisen
abb82154c9 Translated using Weblate (German)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 22:53:06 +02:00
nailyk
03c8b6b5f5 Translated using Weblate (French)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 20:13:20 +02:00
monolifed
2281300165 Translated using Weblate (Turkish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 17:45:46 +02:00
Mauricio Colli
84068d101b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 17:19:26 +02:00
Mauricio Colli
62020fa85b Translated using Weblate (English)
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 17:09:05 +02:00
Mauricio Colli
3c8bf5ccc9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (151 of 151 strings)
2017-06-06 17:06:39 +02:00
Mauricio Colli
71d5762be8 Remove unnecessary check 2017-06-06 11:46:57 -03:00
monolifed
65d5358366 Translated using Weblate (Turkish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-05 22:16:25 +02:00
Mauricio Colli
6ecdfaf19e Improve backstack and theme change 2017-06-05 16:33:01 -03:00
Nathan Follens
32bd6ae1ac Translated using Weblate (Dutch)
Currently translated at 100.0% (151 of 151 strings)
2017-06-05 18:48:51 +02:00
Mauricio Colli
92231a1e26 Translated using Weblate (French)
Currently translated at 98.6% (149 of 151 strings)
2017-06-05 16:13:31 +02:00
Koleon
38ad4dc440 Translated using Weblate (Czech)
Currently translated at 87.4% (132 of 151 strings)
2017-06-05 16:13:30 +02:00
Eduardo Caron
6645a47b0e Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (151 of 151 strings)
2017-06-05 16:05:12 +02:00
Freddy Morán Jr
75a2d20b0b Translated using Weblate (Spanish)
Currently translated at 100.0% (151 of 151 strings)
2017-06-05 16:00:44 +02:00
naofum
8c15d708e6 Translated using Weblate (Japanese)
Currently translated at 100.0% (151 of 151 strings)
2017-06-05 15:57:13 +02:00
Mauricio Colli
539b7ad87b Update some strings.xml files 2017-06-04 21:10:50 -03:00
Mauricio Colli
fc7c2c9f5a Merge remote-tracking branch 'weblate/master' into fix-strings
# Conflicts:
#	app/src/main/res/values-b+ast/strings.xml
#	app/src/main/res/values-fr/strings.xml
#	app/src/main/res/values-pl/strings.xml
#	app/src/main/res/values-pt-rBR/strings.xml
2017-06-04 20:57:00 -03:00
יובל הרמן
3cd760f654 Translated using Weblate (Hebrew)
Currently translated at 60.7% (107 of 176 strings)
2017-06-04 15:45:11 +02:00
Janusz May
2ec0a5d003 Translated using Weblate (Polish)
Currently translated at 100.0% (176 of 176 strings)
2017-06-02 12:52:45 +02:00
OrNicarZ
1a605e814b Translated using Weblate (French)
Currently translated at 99.4% (175 of 176 strings)
2017-06-02 12:52:44 +02:00
יובל הרמן
fe0053a15d Added translation using Weblate (Hebrew) 2017-06-02 12:52:43 +02:00
Eduardo Caron
014f3e5aff Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (176 of 176 strings)
2017-05-31 21:27:25 +02:00
Enol P
4a25e3b644 Translated using Weblate (Asturian)
Currently translated at 98.8% (174 of 176 strings)
2017-05-31 21:27:24 +02:00
anonymous
e7f59bc436 Translated using Weblate (Polish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-31 21:27:22 +02:00
Christian Schabesberger
488d1ccd5a resolve another weblate crash 2017-05-30 22:08:08 +02:00
Janusz May
409b36c254 Translated using Weblate (Polish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-30 17:33:52 +02:00
Janusz May
b0e567dbfa Translated using Weblate (Polish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-30 17:29:14 +02:00
Freddy Morán Jr
c6086ba281 Translated using Weblate (Spanish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-30 16:33:32 +02:00
Marian Hanzel
aede925351 Translated using Weblate (Slovak)
Currently translated at 100.0% (176 of 176 strings)
2017-05-30 16:33:29 +02:00
Christian Schabesberger
9d38c66510 add .weblate to git ignore 2017-05-29 22:50:41 +02:00
Christian Schabesberger
0c516189c3 try to fix another weblate crash 2017-05-29 22:42:23 +02:00
Freddy Morán Jr
c2936ea289 Translated using Weblate (Spanish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-29 15:44:14 +02:00
Gian Maria Viglianti
dc33460a34 Translated using Weblate (Italian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-29 15:44:14 +02:00
anonymous
ffacc93b55 Translated using Weblate (Armenian)
Currently translated at 18.7% (33 of 176 strings)
2017-05-29 15:44:12 +02:00
Christian Schabesberger
74f0ee2718 fix another weblate crash 2017-05-27 18:45:10 +02:00
ktln
7189791d9f Translated using Weblate (Armenian)
Currently translated at 18.1% (32 of 176 strings)
2017-05-27 13:24:00 +02:00
Eduardo Caron
dc18d53c8f Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (176 of 176 strings)
2017-05-27 13:22:42 +02:00
Bruno Guerreiro
f71ef8e130 Translated using Weblate (Portuguese)
Currently translated at 100.0% (176 of 176 strings)
2017-05-27 13:22:41 +02:00
anonymous
6eec9d8993 Translated using Weblate (Armenian)
Currently translated at 18.1% (32 of 176 strings)
2017-05-27 13:22:39 +02:00
Дима Гайнуллин
9560f98359 Translated using Weblate (Russian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-26 01:30:12 +02:00
Eduardo Caron
217433bf69 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (176 of 176 strings)
2017-05-26 01:30:11 +02:00
ktln
ff5db1b939 Translated using Weblate (Armenian)
Currently translated at 16.4% (29 of 176 strings)
2017-05-26 01:30:10 +02:00
Bruno Guerreiro
455a46d3ad Translated using Weblate (Portuguese)
Currently translated at 100.0% (176 of 176 strings)
2017-05-26 01:30:08 +02:00
Christian Schabesberger
039a879104 fix weblate crash 2017-05-25 10:43:17 +02:00
ktln
dfba9ea53b Translated using Weblate (Russian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-25 02:16:14 +02:00
anonymous
177cce5e8f Translated using Weblate (Russian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-25 01:06:23 +02:00
ktln
309d36260e Translated using Weblate (Russian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-25 01:04:29 +02:00
ktln
bdc73eb755 Translated using Weblate (Russian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-25 00:57:39 +02:00
Anton Shestakov
0786750eb9 Translated using Weblate (Russian)
Currently translated at 96.5% (170 of 176 strings)
2017-05-25 00:54:12 +02:00
Слободан Симић(Slobodan Simić)
9f5d921275 Translated using Weblate (Serbian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-25 00:50:25 +02:00
ktln
8991b2d8e3 Translated using Weblate (Armenian)
Currently translated at 7.3% (13 of 176 strings)
2017-05-25 00:50:24 +02:00
ktln
79dffce59b Translated using Weblate (Russian)
Currently translated at 96.5% (170 of 176 strings)
2017-05-25 00:50:22 +02:00
Christian Schabesberger
e0301a621b Merge pull request #575 from mauriciocolli/clean-up-strings
Remove unused strings
2017-05-24 23:29:08 +02:00
Mauricio Colli
1e4361abdc Merge branch 'master' into clean-up-strings 2017-05-24 18:18:50 -03:00
Mauricio Colli
80c26fd278 Merge new translations 2017-05-24 18:11:34 -03:00
Weblate
3339531086 Merge remote-tracking branch 'origin/master' 2017-05-24 18:37:33 +02:00
monolifed
07ad9fbb11 Translated using Weblate (Turkish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-24 18:37:33 +02:00
ktln
6ddc581d76 Translated using Weblate (Russian)
Currently translated at 96.5% (170 of 176 strings)
2017-05-24 18:37:33 +02:00
Слободан Симић(Slobodan Simić)
dfe94172aa Translated using Weblate (Serbian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-24 18:37:30 +02:00
Mauricio Colli
edb632f9c7 Remove unused strings 2017-05-23 11:53:50 -03:00
Christian Schabesberger
7f73612b9f add use english into contribution notes 2017-05-23 11:11:12 +02:00
Christian Schabesberger
7f130f18b6 Merge pull request #573 from sirekanyan/master
Initial string resources for Armenian language
2017-05-23 11:09:50 +02:00
Anton Shestakov
d05a4c53aa Translated using Weblate (Russian)
Currently translated at 93.7% (165 of 176 strings)
2017-05-22 23:38:03 +02:00
ktln
d99a9b90a0 Translated using Weblate (Russian)
Currently translated at 93.1% (164 of 176 strings)
2017-05-22 23:36:37 +02:00
sirekanyan
f311225312 Added initial string resources for Armenian language 2017-05-23 00:26:15 +03:00
Anton Shestakov
dee17fc313 Translated using Weblate (Russian)
Currently translated at 89.7% (158 of 176 strings)
2017-05-22 22:22:08 +02:00
Nathan Follens
0662538d60 Translated using Weblate (Dutch)
Currently translated at 100.0% (176 of 176 strings)
2017-05-21 21:11:27 +02:00
se7entime
5b52ad91ac Translated using Weblate (Indonesian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-21 14:55:38 +02:00
ktln
8552c41bff Translated using Weblate (Russian)
Currently translated at 89.2% (157 of 176 strings)
2017-05-21 08:39:28 +02:00
Weblate
7ecd298285 Merge remote-tracking branch 'origin/master' 2017-05-21 08:35:39 +02:00
Mauricio Colli
2546f515d1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (176 of 176 strings)
2017-05-21 08:35:39 +02:00
naofum
8804924d27 Translated using Weblate (Japanese)
Currently translated at 100.0% (176 of 176 strings)
2017-05-21 08:35:38 +02:00
Anton Shestakov
e410cae141 Translated using Weblate (Russian)
Currently translated at 88.0% (155 of 176 strings)
2017-05-21 08:35:34 +02:00
Christian Schabesberger
140cfaec90 moved on to version 0.9.7 2017-05-20 17:45:50 +02:00
Дима Гайнуллин
a0f20aac23 Translated using Weblate (Russian)
Currently translated at 86.9% (153 of 176 strings)
2017-05-20 15:40:42 +02:00
ktln
93fafb362f Translated using Weblate (Russian)
Currently translated at 86.9% (153 of 176 strings)
2017-05-20 15:39:44 +02:00
anonymous
9152df5512 Translated using Weblate (Russian)
Currently translated at 84.0% (148 of 176 strings)
2017-05-20 15:37:48 +02:00
Anton Shestakov
415bcd9f7e Translated using Weblate (Russian)
Currently translated at 83.5% (147 of 176 strings)
2017-05-20 15:37:13 +02:00
Дима Гайнуллин
2224033a85 Translated using Weblate (Russian)
Currently translated at 82.9% (146 of 176 strings)
2017-05-20 15:36:57 +02:00
Anton Shestakov
ade0498684 Translated using Weblate (Russian)
Currently translated at 82.9% (146 of 176 strings)
2017-05-20 15:34:06 +02:00
Дима Гайнуллин
211b00fff4 Translated using Weblate (Russian)
Currently translated at 82.9% (146 of 176 strings)
2017-05-20 15:33:52 +02:00
ktln
77c72d03a8 Translated using Weblate (Russian)
Currently translated at 82.9% (146 of 176 strings)
2017-05-20 15:32:32 +02:00
Anton Shestakov
f429d93351 Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:25:48 +02:00
Дима Гайнуллин
e428f8b116 Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:20:18 +02:00
Anton Shestakov
9482b9d638 Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:19:15 +02:00
Дима Гайнуллин
e019c9f720 Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:12:17 +02:00
Anton Shestakov
e2778366e9 Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:11:49 +02:00
ktln
36d2f8339c Translated using Weblate (Russian)
Currently translated at 82.3% (145 of 176 strings)
2017-05-20 15:11:30 +02:00
anonymous
a4a0c3b9fd Translated using Weblate (Russian)
Currently translated at 81.2% (143 of 176 strings)
2017-05-20 15:10:44 +02:00
ktln
1b1b6c8af8 Translated using Weblate (Russian)
Currently translated at 80.6% (142 of 176 strings)
2017-05-20 15:10:20 +02:00
Anton Shestakov
064fd2bc68 Translated using Weblate (Russian)
Currently translated at 80.1% (141 of 176 strings)
2017-05-20 15:10:11 +02:00
ktln
13152ab6ea Translated using Weblate (Russian)
Currently translated at 79.5% (140 of 176 strings)
2017-05-20 15:07:58 +02:00
Anton Shestakov
1743d821eb Translated using Weblate (Russian)
Currently translated at 78.9% (139 of 176 strings)
2017-05-20 15:04:08 +02:00
ktln
ff16e577ef Translated using Weblate (Russian)
Currently translated at 78.9% (139 of 176 strings)
2017-05-20 15:02:58 +02:00
Anton Shestakov
86062c6e94 Translated using Weblate (Russian)
Currently translated at 78.4% (138 of 176 strings)
2017-05-20 15:02:43 +02:00
ktln
8ce2350563 Translated using Weblate (Russian)
Currently translated at 78.4% (138 of 176 strings)
2017-05-20 15:00:51 +02:00
Anton Shestakov
cb8989af7f Translated using Weblate (Russian)
Currently translated at 77.8% (137 of 176 strings)
2017-05-20 15:00:25 +02:00
ktln
877fa45eb4 Translated using Weblate (Russian)
Currently translated at 77.2% (136 of 176 strings)
2017-05-20 14:59:24 +02:00
Anton Shestakov
e33942486d Translated using Weblate (Russian)
Currently translated at 76.7% (135 of 176 strings)
2017-05-20 14:58:50 +02:00
Дима Гайнуллин
9606e080ef Translated using Weblate (Russian)
Currently translated at 76.7% (135 of 176 strings)
2017-05-20 14:57:45 +02:00
Anton Shestakov
d5cd9c55be Translated using Weblate (Russian)
Currently translated at 76.7% (135 of 176 strings)
2017-05-20 14:56:39 +02:00
Дима Гайнуллин
9c197ced80 Translated using Weblate (Russian)
Currently translated at 75.0% (132 of 176 strings)
2017-05-20 14:40:15 +02:00
Anton Shestakov
f8424599e1 Translated using Weblate (Russian)
Currently translated at 75.0% (132 of 176 strings)
2017-05-20 14:38:59 +02:00
naofum
ccee18057a Translated using Weblate (Japanese)
Currently translated at 100.0% (176 of 176 strings)
2017-05-20 07:11:53 +02:00
Freddy Morán Jr
1ad0f342ad Translated using Weblate (Spanish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-19 15:39:44 +02:00
Eduardo Caron
7a16ac574b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (176 of 176 strings)
2017-05-19 15:16:03 +02:00
Matej U
f46738f750 Translated using Weblate (Slovenian)
Currently translated at 100.0% (176 of 176 strings)
2017-05-19 13:49:47 +02:00
monolifed
fb8ff3fece Translated using Weblate (Turkish)
Currently translated at 100.0% (176 of 176 strings)
2017-05-19 12:20:03 +02:00
Weblate
7498dd3800 Merge remote-tracking branch 'origin/master' 2017-05-19 03:46:42 +02:00
Freddy Morán Jr
957c31b9c5 Translated using Weblate (Spanish)
Currently translated at 100.0% (172 of 172 strings)
2017-05-19 03:46:40 +02:00
Mauricio Colli
b260570e8c Merge pull request #568 from mauriciocolli/option-search-suggestions
Add option to disable the search suggestions
2017-05-16 22:17:28 -03:00
Mauricio Colli
46542747b7 Merge pull request #567 from mauriciocolli/option-gestures-player
Add option to disable the gesture controls of the player
2017-05-16 22:14:31 -03:00
Mauricio Colli
d64480fc9b Add option to disable the search suggestions 2017-05-16 22:14:07 -03:00
Mauricio Colli
c00e694d40 Add option to disable the gesture controls of the player 2017-05-16 21:45:38 -03:00
Bruno Guerreiro
f0761cc95e Translated using Weblate (Portuguese)
Currently translated at 100.0% (172 of 172 strings)
2017-05-16 21:32:24 +02:00
Eduardo Caron
068554955c Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (172 of 172 strings)
2017-05-16 21:25:48 +02:00
Freddy Morán Jr
a2f915f556 Translated using Weblate (Spanish)
Currently translated at 100.0% (172 of 172 strings)
2017-05-16 14:38:29 +02:00
Mohamad Hasan Al Banna
cffd35c974 Translated using Weblate (Indonesian)
Currently translated at 100.0% (172 of 172 strings)
2017-05-15 17:53:50 +02:00
naofum
2ef2aa98a4 Translated using Weblate (Japanese)
Currently translated at 100.0% (172 of 172 strings)
2017-05-15 17:23:57 +02:00
Théophane
ba98b30aa4 Translated using Weblate (French)
Currently translated at 100.0% (172 of 172 strings)
2017-05-15 16:23:59 +02:00
E T
87c0f9c803 Translated using Weblate (Turkish)
Currently translated at 100.0% (172 of 172 strings)
2017-05-15 16:08:54 +02:00
Matej U
ce620b9e28 Translated using Weblate (Slovenian)
Currently translated at 100.0% (172 of 172 strings)
2017-05-15 14:44:49 +02:00
Weblate
fcbb5536eb Merge remote-tracking branch 'origin/master' 2017-05-15 14:42:35 +02:00
Matej U
72df6dbd80 Translated using Weblate (Slovenian)
Currently translated at 100.0% (171 of 171 strings)
2017-05-15 14:42:32 +02:00
Christian Schabesberger
3a6b023dbf update gradle to version 2.3.2 2017-05-15 12:27:46 +02:00
Mauricio Colli
8b67f1358d Implement no-audio icon 2017-05-15 00:57:57 -03:00
Mauricio Colli
2aebb3b8db Add and update resources 2017-05-15 00:57:04 -03:00
Weblate
f2b38be2b0 Merge remote-tracking branch 'origin/master' 2017-05-14 21:46:25 +02:00
E T
a43001f30d Translated using Weblate (Turkish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-14 21:46:25 +02:00
cwgt
17abe1ea5c Translated using Weblate (Bengali (Bangladesh))
Currently translated at 100.0% (167 of 167 strings)
2017-05-14 21:46:24 +02:00
Bruno Guerreiro
6aaefab618 Translated using Weblate (Portuguese)
Currently translated at 98.2% (168 of 171 strings)
2017-05-14 21:46:22 +02:00
Mauricio Colli
cd867fb4d1 Merge pull request #559 from mauriciocolli/default-popup-resolution
Change popup default resolution
2017-05-14 14:01:12 -03:00
Mauricio Colli
25988f61a6 Change popup default resolution 2017-05-14 13:57:08 -03:00
Mauricio Colli
be421e580d Merge pull request #557 from mauriciocolli/fix-settings-rotation
Fix settings on screen rotation
2017-05-14 11:20:29 -03:00
Mauricio Colli
641ab25470 Fix Settings on screen rotation 2017-05-14 11:10:00 -03:00
Mauricio Colli
a508539c2e Merge pull request #556 from mauriciocolli/fix-audio-focus
Improve behavior on audio focus gain
2017-05-14 10:54:13 -03:00
Mauricio Colli
cac79d9a0d Improve behavior on audio focus gain 2017-05-14 10:46:28 -03:00
Christian Schabesberger
9ede8118da Merge pull request #553 from mauriciocolli/fix-screen-on
Fix keep screen on
2017-05-14 10:48:05 +02:00
Mauricio Colli
e47761750a Fix 'keep screen on' 2017-05-14 00:32:28 -03:00
Christian Schabesberger
2f181ce7c9 move on to version 0.9.6 2017-05-13 22:13:28 +02:00
Christian Schabesberger
3a13d4a1de Merge pull request #546 from mueller-ma/kodi
Change order of buttons in the title bar
2017-05-13 20:16:24 +02:00
Christian Schabesberger
719de00e0f Merge branch 'fix-menu-update' of https://github.com/mauriciocolli/NewPipe 2017-05-13 20:08:18 +02:00
cwgt
ddffe99f53 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 100.0% (167 of 167 strings)
2017-05-13 11:36:43 +02:00
Eduardo Caron
9ade596f06 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (171 of 171 strings)
2017-05-11 20:33:38 +02:00
nailyk
46f413b7f2 Translated using Weblate (French)
Currently translated at 100.0% (171 of 171 strings)
2017-05-11 19:41:37 +02:00
nailyk
5fe2e7b8ad Translated using Weblate (French)
Currently translated at 92.3% (158 of 171 strings)

 popup_mode_share_menu_title a été traduit "Module popup de Newpipe", restons cohérents.
2017-05-11 19:33:46 +02:00
nailyk
3008cbb5f4 Translated using Weblate (French)
Currently translated at 91.8% (157 of 171 strings)
2017-05-11 19:20:57 +02:00
Weblate
f7983960e5 Merge remote-tracking branch 'origin/master' 2017-05-10 21:07:55 +02:00
monolifed
bb8007bb7c Translated using Weblate (Turkish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-10 21:07:55 +02:00
Freddy Morán Jr
01751ba97a Translated using Weblate (Spanish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-10 21:07:55 +02:00
Tobias Groza
f41475d11c Translated using Weblate (German)
Currently translated at 96.4% (165 of 171 strings)
2017-05-10 21:07:54 +02:00
Nathan Follens
d8914d9b6d Translated using Weblate (Dutch)
Currently translated at 100.0% (171 of 171 strings)
2017-05-10 21:07:52 +02:00
mueller-ma
94cc2ad365 change order of buttons, see https://github.com/TeamNewPipe/NewPipe/issues/471#issuecomment-300267118 2017-05-09 20:57:42 +02:00
Christian Schabesberger
e07464b81c Merge pull request #545 from mauriciocolli/fix-image-loader
Fix image loading bug
2017-05-09 20:19:43 +02:00
Jose Maeso
9d231b55b5 Translated using Weblate (Spanish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-09 18:09:23 +02:00
Freddy Morán Jr
77d8dac3c1 Translated using Weblate (Spanish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-09 18:07:54 +02:00
Freddy Morán Jr
e160015283 Translated using Weblate (Spanish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-09 18:05:47 +02:00
mueller-ma
aeb0cac3ee change order of buttons. closes #471 2017-05-09 17:11:19 +02:00
naofum
a539f94837 Translated using Weblate (Japanese)
Currently translated at 100.0% (171 of 171 strings)
2017-05-09 16:19:42 +02:00
monolifed
df70751071 Translated using Weblate (Turkish)
Currently translated at 100.0% (171 of 171 strings)
2017-05-09 14:34:49 +02:00
E T
e55f1dff78 Translated using Weblate (Turkish)
Currently translated at 97.6% (167 of 171 strings)
2017-05-09 14:12:43 +02:00
Weblate
47646e1c62 Merge remote-tracking branch 'origin/master' 2017-05-09 14:11:45 +02:00
E T
80e673f20c Translated using Weblate (Turkish)
Currently translated at 100.0% (167 of 167 strings)
2017-05-09 14:11:41 +02:00
Mauricio Colli
9ca8c5480c Fix image loader bug 2017-05-09 00:12:06 -03:00
Mauricio Colli
4d0d3c7ead Update menu items after change in settings 2017-05-08 22:23:27 -03:00
Christian Schabesberger
58137aadc9 Merge pull request #543 from mueller-ma/patch-1
Remove untranslatable string
2017-05-08 22:45:21 +02:00
mueller-ma
82a59ae479 Remove untranslatable string 2017-05-08 20:51:13 +02:00
Mauricio Colli
affd23b14e Fix animations 2017-05-08 10:33:26 -03:00
Mauricio Colli
9c7f249756 Clean and move some classes 2017-05-08 10:28:33 -03:00
Christian Schabesberger
e2a0502171 Merge pull request #538 from cwgt/bn-bd-translation
Add Bangla translation (for Bangladesh)
2017-05-08 11:44:27 +02:00
cwgt
3832a4b355 Add Bangla translation (for Bangladesh) 2017-05-08 15:27:55 +06:00
cwgt
84f059415c Create strings.xml 2017-05-08 13:32:33 +06:00
Christian Schabesberger
bb292e3199 add some more screenshots 2017-05-07 20:41:44 +02:00
Christian Schabesberger
70541bf561 moved on to version 0.9.5 2017-05-07 20:05:00 +02:00
Christian Schabesberger
48dd8e88e3 Merge branch 'master' of github.com:theScrabi/NewPipe 2017-05-07 19:48:21 +02:00
Eduardo Caron
52c2e0899d Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.4% (166 of 167 strings)
2017-05-07 18:46:09 +02:00
Christian Schabesberger
9955d5b62f Merge branch 'resize' 2017-05-04 21:31:38 +02:00
Marian Hanzel
8e26247fa1 Translated using Weblate (Slovak)
Currently translated at 100.0% (167 of 167 strings)
2017-05-04 21:02:23 +02:00
Weblate
72924e2692 Merge remote-tracking branch 'origin/master' 2017-05-04 18:46:39 +02:00
Eduardo Caron
8c2c8d630f Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (165 of 167 strings)
2017-05-04 18:46:39 +02:00
Freddy Morán Jr
5ccf0baa6b Translated using Weblate (Spanish)
Currently translated at 100.0% (167 of 167 strings)
2017-05-04 18:46:36 +02:00
Christian Schabesberger
8fff0ccdf2 Merge pull request #532 from mauriciocolli/improve-readme
Update Readme
2017-05-04 00:10:44 +02:00
Mauricio Colli
35264bfb97 Update Readme 2017-05-03 16:13:31 -03:00
Matej U
4c9b0dc8e9 Translated using Weblate (Slovenian)
Currently translated at 100.0% (167 of 167 strings)
2017-05-02 21:02:58 +02:00
Freddy Morán Jr
4deb7caa83 Translated using Weblate (Spanish)
Currently translated at 100.0% (167 of 167 strings)
2017-05-02 17:22:14 +02:00
Enol P
45f1a512b4 Translated using Weblate (Asturian)
Currently translated at 98.2% (164 of 167 strings)
2017-05-01 18:44:12 +02:00
Mladen Pejaković
ab95fdc087 Translated using Weblate (Serbian)
Currently translated at 99.4% (166 of 167 strings)
2017-05-01 15:46:36 +02:00
Christian Schabesberger
df608b9ded Merge branch 'feature-resize' of https://github.com/mauriciocolli/NewPipe into resize 2017-05-01 15:15:30 +02:00
Tobias Groza
6a4c81d160 Translated using Weblate (German)
Currently translated at 98.2% (164 of 167 strings)
2017-05-01 12:45:14 +02:00
Mauricio Colli
040d658540 Implement resizable popup 2017-05-01 02:23:50 -03:00
naofum
cbc9913e9c Translated using Weblate (Japanese)
Currently translated at 100.0% (167 of 167 strings)
2017-04-30 05:47:23 +02:00
Wout Bertrums
f007cbd5ee Translated using Weblate (Dutch)
Currently translated at 100.0% (167 of 167 strings)
2017-04-29 18:46:39 +02:00
zmni
7351591df7 Translated using Weblate (Indonesian)
Currently translated at 100.0% (167 of 167 strings)
2017-04-29 16:52:22 +02:00
monolifed
5222d4cbba Translated using Weblate (Turkish)
Currently translated at 100.0% (167 of 167 strings)
2017-04-29 09:48:33 +02:00
Weblate
ef9966815e Merge remote-tracking branch 'origin/master' 2017-04-29 08:27:55 +02:00
anonymous
ad73440ce9 Translated using Weblate (Czech)
Currently translated at 93.9% (154 of 164 strings)
2017-04-29 08:27:51 +02:00
Christian Schabesberger
c81cfdc455 moved on to version 0.9.4 2017-04-28 21:26:11 +02:00
Christian Schabesberger
134c3804db Merge branch 'fix-search' of https://github.com/mauriciocolli/NewPipe into fix-search 2017-04-28 20:42:37 +02:00
Christian Schabesberger
e355df5eda update NewPipeExtractor 2017-04-28 20:19:23 +02:00
Mauricio Colli
a68e0a95f4 Fix NullPointerException 2017-04-28 01:07:54 -03:00
Mauricio Colli
6fd6facf72 Improve animations of VideoDetailFragment 2017-04-28 00:58:50 -03:00
Mauricio Colli
00102d4048 Try to fix travis 2017-04-26 17:07:24 -03:00
Mauricio Colli
adbeff11d4 Minor improvements 2017-04-26 16:32:20 -03:00
Mauricio Colli
a8fe329678 Improve fragments
- They save the state now, that means, no more reloading after rotating the screen or switching between apps
2017-04-26 16:32:04 -03:00
Mauricio Colli
a4b61bf730 Add new workers 2017-04-26 16:25:09 -03:00
Mauricio Colli
ee592def0c Add drawables and improve layouts 2017-04-26 16:24:33 -03:00
Allan Nordhøy
c14e117239 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (164 of 164 strings)
2017-04-25 03:46:10 +02:00
rapi3
b6e94dde0c Translated using Weblate (Romanian)
Currently translated at 100.0% (164 of 164 strings)
2017-04-23 15:46:17 +02:00
monolifed
63a4a44d7e Translated using Weblate (Turkish)
Currently translated at 100.0% (164 of 164 strings)
2017-04-23 12:46:56 +02:00
Allan Nordhøy
eb8ab5d527 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (164 of 164 strings)
2017-04-23 00:57:22 +02:00
riotism
b778d40d65 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 97.5% (160 of 164 strings)
2017-04-22 18:44:35 +02:00
rapi3
2f570672dc Translated using Weblate (Romanian)
Currently translated at 100.0% (164 of 164 strings)
2017-04-21 14:11:07 +02:00
anonymous
9290ed490f Translated using Weblate (Turkish)
Currently translated at 100.0% (164 of 164 strings)
2017-04-21 11:12:23 +02:00
monolifed
1bda812c75 Translated using Weblate (Turkish)
Currently translated at 100.0% (164 of 164 strings)
2017-04-21 11:11:23 +02:00
Weblate
ab82406c98 Merge remote-tracking branch 'origin/master' 2017-04-19 17:36:17 +02:00
Mladen Pejaković
be763349df Translated using Weblate (Serbian)
Currently translated at 99.3% (163 of 164 strings)
2017-04-19 17:36:16 +02:00
zmni
91764ad601 Translated using Weblate (Indonesian)
Currently translated at 100.0% (164 of 164 strings)
2017-04-19 17:36:14 +02:00
Christian Schabesberger
1c4031aa38 Merge branch 'master' of github.com:theScrabi/NewPipe 2017-04-18 22:39:16 +02:00
Christian Schabesberger
c3bc648dd4 moved on to version 0.9.3 2017-04-18 22:34:32 +02:00
Christian Schabesberger
c97d794272 updated sdk and support lib 2017-04-18 22:34:04 +02:00
Christian Schabesberger
8e7d2e91e9 Merge branch 'feature-backplayer' of https://github.com/mauriciocolli/NewPipe into mark 2017-04-18 22:06:47 +02:00
Laura Arjona Reina
cf0fbbbd3d Translated using Weblate (Spanish)
Currently translated at 100.0% (164 of 164 strings)
2017-04-18 20:19:12 +02:00
Tobias Groza
7d3ede7946 Translated using Weblate (German)
Currently translated at 100.0% (164 of 164 strings)
2017-04-18 12:58:44 +02:00
Eduardo Caron
1aa308eb5d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (164 of 164 strings)
2017-04-18 00:35:02 +02:00
anonymous
4bfd30e34a Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.3% (163 of 164 strings)
2017-04-18 00:28:43 +02:00
Eduardo Caron
0f46c90688 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.3% (163 of 164 strings)
2017-04-18 00:27:31 +02:00
Matej U
aa2173fc4a Translated using Weblate (Slovenian)
Currently translated at 100.0% (164 of 164 strings)
2017-04-17 18:09:10 +02:00
Mauricio Colli
932cb1d19c Remove ugly bitmap sharing and improvements
- Now it is just using the ImageLoader to load the image, and better yet, it already have cache implemented in it
- Improve MainActivity intent handler
- Improve utils classes
2017-04-17 01:21:48 -03:00
Mauricio Colli
18b038d8e4 Improve notification layouts 2017-04-17 01:20:14 -03:00
Mauricio Colli
2ac71c75c0 Improve players
- Background player is using ExoPlayer internally now
2017-04-17 01:19:53 -03:00
naofum
4067ba5232 Translated using Weblate (Japanese)
Currently translated at 100.0% (164 of 164 strings)
2017-04-16 16:48:37 +02:00
Marian Hanzel
ab47dd5a5b Translated using Weblate (Slovak)
Currently translated at 100.0% (164 of 164 strings)
2017-04-15 22:32:17 +02:00
Nathan Follens
3130910307 Translated using Weblate (Dutch)
Currently translated at 100.0% (164 of 164 strings)
2017-04-15 17:35:12 +02:00
Sérgio Marques
22113439a4 Translated using Weblate (Portuguese)
Currently translated at 100.0% (164 of 164 strings)
2017-04-15 16:09:58 +02:00
Weblate
2d25a9ad7a Merge remote-tracking branch 'origin/master' 2017-04-15 16:07:22 +02:00
Freddy Morán Jr
8f0a2cc2f0 Translated using Weblate (Spanish)
Currently translated at 100.0% (161 of 161 strings)
2017-04-15 16:07:22 +02:00
Marian Hanzel
4ca39258c9 Translated using Weblate (Slovak)
Currently translated at 100.0% (161 of 161 strings)
2017-04-15 16:07:21 +02:00
Enol P
d0c0238b8b Translated using Weblate (Asturian)
Currently translated at 98.1% (158 of 161 strings)
2017-04-15 16:07:20 +02:00
Sérgio Marques
f9f08e5169 Translated using Weblate (Portuguese)
Currently translated at 100.0% (161 of 161 strings)
2017-04-15 16:07:18 +02:00
Christian Schabesberger
cfc51b2401 Merge branch 'master' of github.com:theScrabi/NewPipe 2017-04-15 14:05:39 +02:00
Christian Schabesberger
54c2704cb5 switch to dark default theme 2017-04-15 14:05:31 +02:00
Christian Schabesberger
9b51c946fe add 1080p to available features 2017-04-15 13:43:21 +02:00
Christian Schabesberger
06f38cbcb4 Merge branch 'feature-4k60f' of git://github.com/mauriciocolli/NewPipe into 4k 2017-04-15 12:52:03 +02:00
Christian Schabesberger
f368d6b257 update extractor 2017-04-15 12:51:35 +02:00
Marian Hanzel
f4301da14d Translated using Weblate (Slovak)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 21:49:26 +02:00
Weblate
f34c09f165 Merge remote-tracking branch 'origin/master' 2017-04-13 20:51:06 +02:00
Freddy Morán Jr
6d1db56512 Translated using Weblate (Spanish)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 20:51:03 +02:00
Christian Schabesberger
b70c07d004 update extractor 2017-04-13 19:41:43 +02:00
Christian Schabesberger
f9f48a5eb6 Merge branch 'master' of github.com:theScrabi/NewPipe 2017-04-13 19:41:28 +02:00
Christian Schabesberger
14e4e73444 update gradle 2017-04-13 19:41:15 +02:00
Nathan Follens
f2ce4d2daf Translated using Weblate (Dutch)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 19:10:56 +02:00
naofum
468ebdda87 Translated using Weblate (Japanese)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 16:53:26 +02:00
nautilusx
a1f0fb3b14 Translated using Weblate (German)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 16:08:34 +02:00
zmni
3c9f4de234 Translated using Weblate (Indonesian)
Currently translated at 100.0% (161 of 161 strings)
2017-04-13 15:59:13 +02:00
Tobias Groza
8ae411619f Translated using Weblate (German)
Currently translated at 96.8% (156 of 161 strings)
2017-04-13 15:56:35 +02:00
nautilusx
61e5c9121a Translated using Weblate (German)
Currently translated at 96.2% (155 of 161 strings)
2017-04-13 15:55:28 +02:00
Weblate
8a3cf0d5dc Merge remote-tracking branch 'origin/master' 2017-04-13 15:53:52 +02:00
Freddy Morán Jr
ecb5df65ac Translated using Weblate (Spanish)
Currently translated at 100.0% (160 of 160 strings)
2017-04-13 15:53:52 +02:00
anonymous
5f1e98a0d3 Translated using Weblate (German)
Currently translated at 96.2% (154 of 160 strings)
2017-04-13 15:53:49 +02:00
Mauricio Colli
3b9a477499 Add resolution support up to 4k and 60 fps
- Up to 4k with 60 fps
    - Not every device can play in that resolution and bitrate
    - Add option to hide these high resolution greater than 1080p (2k,4k) for not clutter the menus
- Add a default resolution for the popup, wil be used when opening in popup mode from another app
2017-04-12 03:07:15 -03:00
Christian Schabesberger
e5bf98a741 move on to version 0.9.2 2017-04-11 22:51:04 +02:00
Christian Schabesberger
06fafc247e move to version 0.9.2 of NewPipeExtractor 2017-04-11 22:49:18 +02:00
Christian Schabesberger
e8bb17b631 Merge branch 'fix-next-video' of git://github.com/mauriciocolli/NewPipe into mul 2017-04-11 22:26:41 +02:00
Freddy Morán Jr
363cd07883 Translated using Weblate (Spanish)
Currently translated at 100.0% (160 of 160 strings)
2017-04-11 18:56:03 +02:00
Mladen Pejaković
2b4a9286c4 Translated using Weblate (Serbian)
Currently translated at 99.3% (159 of 160 strings)
2017-04-11 00:46:21 +02:00
Nathan Follens
34c985026f Translated using Weblate (Dutch)
Currently translated at 100.0% (160 of 160 strings)
2017-04-10 17:40:52 +02:00
naofum
4a0aa42914 Translated using Weblate (Japanese)
Currently translated at 100.0% (160 of 160 strings)
2017-04-10 17:21:54 +02:00
Mauricio Colli
746c2a15bf Migrate to fragments and improvements
- Migrate to fragments
- Fix #487
- Don't show "Open in popup mode" to channel links
- New backstack of videos
- Change the subscribers count to format using `NumberFormat`, for example some locales use `.`  others `,`, this handles it automatically (and the old method had a bug for leading zero, e.g. 4.82.125 instead of 4.082.125)
- Add string 'subscribers' for channels with more than 1 subscriber (plural)
- Popup player chooses the default format and resolution based on the new preference (format)
- Fix taskaffinity of the router activities
- Show title before loading, as it is available from the items already loaded
2017-04-09 14:34:00 -03:00
zmni
9318bb5306 Translated using Weblate (Indonesian)
Currently translated at 100.0% (160 of 160 strings)
2017-04-09 07:39:53 +02:00
Matej U
2a10ceb74f Translated using Weblate (Slovenian)
Currently translated at 100.0% (160 of 160 strings)
2017-04-08 22:08:31 +02:00
Weblate
83f4db59e2 Merge remote-tracking branch 'origin/master' 2017-04-08 21:47:50 +02:00
Olexandr Nesterenko
9f66f759ad Translated using Weblate (Ukrainian)
Currently translated at 84.9% (135 of 159 strings)
2017-04-08 21:47:47 +02:00
Christian Schabesberger
6f015349e8 moved on to v0.9.1 2017-04-08 17:17:58 +02:00
Christian Schabesberger
a37802c2b9 add prefered video format 2017-04-08 17:17:11 +02:00
Florian
4fa3baf5e1 Translated using Weblate (French)
Currently translated at 99.3% (158 of 159 strings)
2017-04-07 12:45:03 +02:00
Oscar Hemelaar
ef8c2c81d5 Translated using Weblate (Italian)
Currently translated at 98.7% (157 of 159 strings)
2017-04-07 03:45:31 +02:00
Mladen Pejaković
8c80d8c457 Translated using Weblate (Serbian)
Currently translated at 99.3% (158 of 159 strings)
2017-04-07 00:46:25 +02:00
Matej U
1596872c54 Translated using Weblate (Slovenian)
Currently translated at 100.0% (159 of 159 strings)
2017-04-05 14:47:22 +02:00
Oscar Hemelaar
da8873fa78 Translated using Weblate (French)
Currently translated at 99.3% (158 of 159 strings)
2017-04-05 12:14:32 +02:00
Oscar Hemelaar
ecd8439b3f Translated using Weblate (French)
Currently translated at 98.1% (156 of 159 strings)

if it's for a video restart button, it's "Relancer"
2017-04-05 02:53:08 +02:00
Oscar Hemelaar
5d178532ac Translated using Weblate (French)
Currently translated at 97.4% (155 of 159 strings)
2017-04-05 02:52:24 +02:00
Oscar Hemelaar
08e40a013d Translated using Weblate (French)
Currently translated at 96.8% (154 of 159 strings)

or "OK" ?
2017-04-05 02:50:49 +02:00
Oscar Hemelaar
c136f7363c Translated using Weblate (French)
Currently translated at 96.2% (153 of 159 strings)
2017-04-05 02:50:26 +02:00
Florian
a60f10d739 Translated using Weblate (French)
Currently translated at 90.5% (144 of 159 strings)
2017-04-04 21:45:44 +02:00
naofum
ae46afcb42 Translated using Weblate (Japanese)
Currently translated at 100.0% (159 of 159 strings)
2017-04-04 16:15:27 +02:00
mueller-ma
bffb9f6800 Translated using Weblate (German)
Currently translated at 95.5% (152 of 159 strings)
2017-04-03 09:29:35 +02:00
Tobias Groza
79aa9ad04b Translated using Weblate (German)
Currently translated at 94.9% (151 of 159 strings)
2017-04-03 09:26:41 +02:00
anonymous
ff5714f04a Translated using Weblate (French)
Currently translated at 89.9% (143 of 159 strings)
2017-04-02 18:59:25 +02:00
zmni
ce499a9766 Translated using Weblate (Indonesian)
Currently translated at 100.0% (159 of 159 strings)
2017-04-02 16:49:33 +02:00
Weblate
d3bb8b7651 Merge remote-tracking branch 'origin/master' 2017-04-02 16:48:37 +02:00
Freddy Morán Jr
6d9c23c4cb Translated using Weblate (Spanish)
Currently translated at 100.0% (158 of 158 strings)
2017-04-02 16:48:36 +02:00
Nathan Follens
b95a9332a9 Translated using Weblate (Dutch)
Currently translated at 100.0% (158 of 158 strings)
2017-04-02 16:48:35 +02:00
zmni
609715eb5c Translated using Weblate (Indonesian)
Currently translated at 100.0% (158 of 158 strings)
2017-04-02 16:48:33 +02:00
Christian Schabesberger
a1266c919c Merge branch 'fix-next-video' of git://github.com/mauriciocolli/NewPipe into strfx 2017-04-02 15:56:41 +02:00
Christian Schabesberger
a1925a0302 Merge branch 'master' of github.com:theScrabi/NewPipe 2017-04-02 15:48:53 +02:00
Christian Schabesberger
a7a4c03372 update features list, and moved on to v0.9.0 2017-04-02 15:47:21 +02:00
Christian Schabesberger
37201600e0 Merge pull request #494 from mueller-ma/patch-1
Fix list in readme
2017-04-02 15:44:14 +02:00
mueller-ma
a94f40ed62 Fix list in readme 2017-04-02 14:33:52 +02:00
naofum
0b08cf8c76 Translated using Weblate (Japanese)
Currently translated at 100.0% (158 of 158 strings)
2017-04-01 13:36:04 +02:00
Mauricio Colli
33e29be7db Fix next video and refactor
- Refactor VideoItemDetailActivity, StreamExtractorWorker
- Remove redundant styles
- Change dimensions
- Nicer animation/transitions
2017-03-31 20:39:54 -03:00
Freddy Morán Jr
bd1c7851c7 Translated using Weblate (Portuguese)
Currently translated at 100.0% (158 of 158 strings)
2017-04-01 01:02:49 +02:00
Freddy Morán Jr
82faea5965 Translated using Weblate (Spanish)
Currently translated at 100.0% (158 of 158 strings)
2017-04-01 00:51:34 +02:00
Weblate
0bbbfd3217 Merge remote-tracking branch 'origin/master' 2017-04-01 00:44:52 +02:00
Freddy Morán Jr
fb578ecda8 Translated using Weblate (Spanish)
Currently translated at 100.0% (156 of 156 strings)
2017-04-01 00:44:41 +02:00
Christian Schabesberger
e804647a65 make exoplayer default player 2017-03-29 09:17:03 +02:00
Christian Schabesberger
c3c3a94593 Merge branch 'feature-popup-fullscreen' of git://github.com/mauriciocolli/NewPipe into toogle 2017-03-29 08:48:00 +02:00
Mauricio Colli
9d55569f80 Fix keep screen on 2017-03-28 09:12:03 -03:00
Christian Schabesberger
5dd8271c15 Merge pull request #489 from mauriciocolli/master
Fix travis and some clean-up
2017-03-27 23:53:04 +02:00
Mauricio Colli
7a4a54c3ea Fix travis
- Remove duplicate of AndroidManifest
- Remove some non-translatable strings from "ar" translation, and general clean-up of other
2017-03-27 16:34:37 -03:00
Mauricio Colli
7c9078a625 Fix non-commited file 2017-03-27 11:26:36 -03:00
Mauricio Colli
71ae342f52 Implement screen orientation toggle 2017-03-27 10:12:22 -03:00
Mauricio Colli
b43c56085d Implement fullscreen and quality selector
- Implement cache
- Abstract player
- Quality selector
- Fullscreen switcher
- Change some drawables
2017-03-27 01:08:16 -03:00
Christian Schabesberger
83d2ab95e0 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2017-03-26 17:29:25 +02:00
Christian Schabesberger
20a8d7372c fix broken overlay on .svg icon 2017-03-26 17:29:16 +02:00
Weblate
c36ba88db7 Merge remote-tracking branch 'origin/master' 2017-03-25 14:05:16 +01:00
Nathan Follens
4aa23023ee Translated using Weblate (Dutch)
Currently translated at 100.0% (156 of 156 strings)
2017-03-25 14:05:13 +01:00
Christian Schabesberger
8735cf931a update to new backend with playlist support 2017-03-22 20:14:56 +01:00
Weblate
2473069326 Merge remote-tracking branch 'origin/master' 2017-03-21 09:44:34 +01:00
vesp
03bab57a97 Translated using Weblate (Czech)
Currently translated at 99.3% (155 of 156 strings)
2017-03-21 09:44:32 +01:00
Christian Schabesberger
e3baf69533 fix channel rotation problem 2017-03-17 20:35:22 +01:00
Christian Schabesberger
461f747af1 add IOException 2017-03-17 20:18:44 +01:00
Christian Schabesberger
028872a7d8 Merge pull request #483 from mauriciocolli/patch-2
Fix bug when fetching unavailable content
2017-03-17 17:10:03 +01:00
Christian Schabesberger
a1483b6c55 Merge pull request #481 from mauriciocolli/patch-1
Handle embed links
2017-03-17 17:09:13 +01:00
mauriciocolli
e406ba094c Improve bug detection
- Show a message with the appropriate error (network error)
2017-03-17 12:09:20 -03:00
mauriciocolli
c100d15ba8 Fix bug when fetching unavailable content
- Fix #482
- When opening a invalid/deleted/unavailable video, the popup was just printing the error, now it shows a message to the user and exits
2017-03-17 11:50:27 -03:00
mauriciocolli
b4ea592638 Handle embed links
- Fix #480
- Add /embed/ to intent filter, as the app already handles these type of links internally
2017-03-17 00:27:59 -03:00
Sérgio Marques
16b757d9a3 Translated using Weblate (Portuguese)
Currently translated at 100.0% (156 of 156 strings)
2017-03-17 00:46:17 +01:00
Sérgio Marques
2aa801a392 Translated using Weblate (Portuguese)
Currently translated at 100.0% (156 of 156 strings)
2017-03-14 23:24:24 +01:00
Matej U
b838344526 Translated using Weblate (Slovenian)
Currently translated at 100.0% (156 of 156 strings)
2017-03-13 10:30:41 +01:00
zmni
233a3df222 Translated using Weblate (Indonesian)
Currently translated at 100.0% (156 of 156 strings)
2017-03-11 13:27:00 +01:00
naofum
da6661b1ea Translated using Weblate (Japanese)
Currently translated at 100.0% (156 of 156 strings)
2017-03-11 12:37:49 +01:00
Mladen Pejaković
c6e120fc51 Translated using Weblate (Serbian)
Currently translated at 100.0% (156 of 156 strings)
2017-03-10 23:09:42 +01:00
Marian Hanzel
c416a1254d Translated using Weblate (Slovak)
Currently translated at 100.0% (156 of 156 strings)
2017-03-10 23:07:10 +01:00
Weblate
2aa4f6ddda Merge remote-tracking branch 'origin/master' 2017-03-10 21:45:11 +01:00
Enrico Monese
129597023d Translated using Weblate (Italian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-10 21:45:10 +01:00
vesp
02aed86b7e Translated using Weblate (Czech)
Currently translated at 98.7% (152 of 154 strings)
2017-03-10 21:45:10 +01:00
Tobias Groza
e44f4b5823 Translated using Weblate (German)
Currently translated at 98.7% (152 of 154 strings)
2017-03-10 21:45:08 +01:00
Christian Schabesberger
2f0c0f0fc2 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2017-03-09 16:21:36 +01:00
Christian Schabesberger
e5ce3f3007 moved on to version 0.8.12 2017-03-09 16:21:20 +01:00
Christian Schabesberger
095a2be748 change popuplayer class description 2017-03-09 16:14:49 +01:00
Christian Schabesberger
c75fe88757 Merge branch 'feature-popup' of git://github.com/mauriciocolli/NewPipe 2017-03-09 16:08:33 +01:00
Christian Schabesberger
a8ff4b0744 Fix backbutton behaviour
- close on MainActivity when back pressed
- clear NavStack on rotation
2017-03-09 16:01:09 +01:00
Christian Schabesberger
c02c511e31 Update .travis.yml
update build-tools version for travis
2017-03-09 15:41:10 +01:00
Mauricio Colli
b9550fb528 Merge remote-tracking branch 'upstream/master' into feature-popup 2017-03-09 04:49:15 -03:00
Mauricio Colli
a37d8f083a Implement popup mode
- Add icons replay, fast_forward
- Add strings
- Add menu entry
- Add as option to open link directly to popup mode
2017-03-09 04:42:40 -03:00
Mauricio Colli
abff1f537b Add ExoMedia and remove ExoPlayer
- Remove ExoPlayer files
- Added ExoMedia library
2017-03-09 01:44:00 -03:00
Enrico Monese
483fde5e42 Translated using Weblate (Italian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-08 23:52:45 +01:00
Weblate
761b7ea57b Merge remote-tracking branch 'origin/master' 2017-03-07 18:45:34 +01:00
zmni
af92631a0c Translated using Weblate (Indonesian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-07 18:45:29 +01:00
Christian Schabesberger
ffe832d061 update gradle verson 2017-03-07 14:14:02 +01:00
Christian Schabesberger
a08cbfcef1 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2017-03-06 15:36:13 +01:00
Christian Schabesberger
d2d6ac1bf8 add CCC slides 2017-03-06 15:36:04 +01:00
Weblate
615ffca64b Merge remote-tracking branch 'origin/master' 2017-03-05 16:35:55 +01:00
Tobias Groza
2fcf6197c5 Translated using Weblate (German)
Currently translated at 97.4% (150 of 154 strings)
2017-03-05 16:35:54 +01:00
zmni
22d31ae14f Translated using Weblate (Indonesian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-05 16:35:52 +01:00
Christian Schabesberger
8c786e121b get down to support lib 25.1.0 2017-03-04 13:30:21 +01:00
Christian Schabesberger
99d2a33c8c reset support lib to 25.1.1
25.2.0 is not yet supported by fdroid
2017-03-04 13:23:54 +01:00
Marian Hanzel
010a24db3f Translated using Weblate (Slovak)
Currently translated at 100.0% (154 of 154 strings)
2017-03-04 10:57:28 +01:00
Weblate
9408da453b Merge remote-tracking branch 'origin/master' 2017-03-02 15:26:33 +01:00
Jose Maeso
dbda4202fd Translated using Weblate (Spanish)
Currently translated at 98.7% (152 of 154 strings)
2017-03-02 15:26:32 +01:00
Mladen Pejaković
5776e91459 Translated using Weblate (Serbian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-02 15:26:32 +01:00
Matej U
664d7b69b1 Translated using Weblate (Slovenian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-02 15:26:30 +01:00
Christian Schabesberger
6b9140c60d make extractor sub use https 2017-03-01 19:25:19 +01:00
Christian Schabesberger
383857d110 add extractor submodule 2017-03-01 19:08:12 +01:00
Christian Schabesberger
cffd049c8a remove extractor 2017-03-01 19:06:27 +01:00
Christian Schabesberger
ecabc65e94 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2017-03-01 18:03:50 +01:00
Christian Schabesberger
780f1d5da3 made extractor systemindipendent again 2017-03-01 18:03:36 +01:00
naofum
e2d0fc34a3 Translated using Weblate (Japanese)
Currently translated at 100.0% (154 of 154 strings)
2017-03-01 17:41:48 +01:00
Christian Schabesberger
3404231457 get rid of xul xml parser 2017-03-01 16:40:04 +01:00
Mladen Pejaković
b17928570d Translated using Weblate (Serbian)
Currently translated at 100.0% (154 of 154 strings)
2017-03-01 14:15:48 +01:00
Weblate
8ed86261ef Merge remote-tracking branch 'origin/master' 2017-03-01 12:45:58 +01:00
RACER
a313b91a0a Translated using Weblate (Japanese)
Currently translated at 100.0% (149 of 149 strings)
2017-03-01 12:45:45 +01:00
Christian Schabesberger
7b6dae20be add loading footer to search fragment 2017-02-28 13:24:07 +01:00
Christian Schabesberger
552c70bb0d add adblocker for youtube red stuff 2017-02-28 13:05:20 +01:00
Christian Schabesberger
8f734737f0 fix bug and add footer cycle to channel 2017-02-28 12:13:29 +01:00
Christian Schabesberger
800e7bcb7a moved on to v0.8.11 2017-02-27 21:37:22 +01:00
Christian Schabesberger
2002234d86 fix channel load more videos error 2017-02-27 21:31:20 +01:00
Christian Schabesberger
5923663e08 add routed_intent activity 2017-02-27 21:14:03 +01:00
Christian Schabesberger
4cdf20ab8c fix differences 2017-02-27 19:21:41 +01:00
Christian Schabesberger
af65a1cfef Merge branch 'feature-theme-change' of git://github.com/mauriciocolli/NewPipe into conf 2017-02-27 19:04:38 +01:00
Christian Schabesberger
927057ab83 Merge pull request #465 from mauriciocolli/fix-travis
Fix travis and YoutubeStreamUrlIdHandler
2017-02-27 19:03:28 +01:00
Christian Schabesberger
ffbc001ad5 fix navstack channel problem 2017-02-27 19:00:06 +01:00
Christian Schabesberger
f5625a1151 fix dashmpd bug 2017-02-27 17:57:16 +01:00
Christian Schabesberger
ce2ceb8a1b fix layout 2017-02-27 16:38:01 +01:00
Christian Schabesberger
c14771534f redesign channel activity 2017-02-27 15:58:09 +01:00
59436419
553cec16d5 Removed old icons 2017-02-27 17:30:47 +05:30
59436419
d17496f720 Improved code for changing theme 2017-02-27 17:25:15 +05:30
Christian Schabesberger
89e70626eb update support framework 2017-02-26 21:38:02 +01:00
Mauricio Colli
2ccae841d6 Change variable names
For a better understanding of what is going on
2017-02-26 07:47:13 -03:00
Mauricio Colli
07f6d0f149 Fix bug lower case id
This method was passing the lowercase url
2017-02-25 18:15:50 -03:00
Mauricio Colli
319d769233 Change video Id
The previous wasn't working
2017-02-25 18:14:32 -03:00
Mauricio Colli
6ec393699e Check if selected theme it's not the current 2017-02-25 16:04:10 -03:00
Mauricio Colli
f8d9e0fa60 Implement restart dialog 2017-02-25 15:36:31 -03:00
Mauricio Colli
50ed962a82 Add necessary strings 2017-02-25 15:34:45 -03:00
Christian Schabesberger
8654705e9b Change T to K 2017-02-22 12:12:39 +01:00
Weblate
b79ed8185f Merge remote-tracking branch 'origin/master' 2017-02-21 17:48:35 +01:00
Rom1
0d6c67f64f Translated using Weblate (French)
Currently translated at 96.6% (144 of 149 strings)
2017-02-21 17:48:34 +01:00
Marian Hanzel
e97a6569a6 Translated using Weblate (Slovak)
Currently translated at 100.0% (149 of 149 strings)
2017-02-21 17:48:32 +01:00
Christian Schabesberger
d0d41c6b16 move on to v0.8.10 2017-02-19 16:09:39 +01:00
Christian Schabesberger
f7a531e71b Merge branch 'fix_nav' 2017-02-19 16:09:02 +01:00
Christian Schabesberger
c28fddc4dd did some finetuning 2017-02-19 16:07:45 +01:00
zmni
b6ea10fc73 Translated using Weblate (Indonesian)
Currently translated at 100.0% (149 of 149 strings)
2017-02-19 15:45:16 +01:00
Gian Maria Viglianti
320eb44061 Translated using Weblate (Italian)
Currently translated at 100.0% (149 of 149 strings)
2017-02-19 00:54:12 +01:00
Christian Schabesberger
7a6b5dd5b7 add initial support for NavStack 2017-02-18 21:59:48 +01:00
naofum
460653ed16 Translated using Weblate (Japanese)
Currently translated at 100.0% (149 of 149 strings)
2017-02-17 16:18:49 +01:00
Mladen Pejaković
b6fda788c5 Translated using Weblate (Serbian)
Currently translated at 100.0% (149 of 149 strings)
2017-02-16 22:12:17 +01:00
Matej U
da4b9306fa Translated using Weblate (Slovenian)
Currently translated at 100.0% (149 of 149 strings)
2017-02-16 22:00:25 +01:00
Weblate
d76c02cbf4 Merge remote-tracking branch 'origin/master' 2017-02-16 21:44:49 +01:00
nonamebg
4d5466b5cd Translated using Weblate (English)
Currently translated at 100.0% (141 of 141 strings)
2017-02-16 21:44:40 +01:00
Christian Schabesberger
e9c20ac8b0 add search channels to available features 2017-02-16 13:57:48 +01:00
Christian Schabesberger
961820a250 Merge branch 'search_channel' 2017-02-16 13:33:46 +01:00
Christian Schabesberger
4cc2976061 add unit test for new channel search 2017-02-16 00:46:15 +01:00
Christian Schabesberger
477f182b43 convert android tests to junit tests 2017-02-16 00:17:43 +01:00
Christian Schabesberger
a5252bb765 add search filter menu 2017-02-15 15:21:36 +01:00
Christian Schabesberger
3f0078f38a git channel item running 2017-02-15 12:59:36 +01:00
Christian Schabesberger
91434dd2ac setup core for search channel support 2017-02-13 00:55:11 +01:00
Christian Schabesberger
f29bd0a6e7 fix actionbar icon theming 2017-02-12 16:45:01 +01:00
Christian Schabesberger
7186f58374 remove StreamInfoItemSearchCollector 2017-02-12 14:22:39 +01:00
Christian Schabesberger
5c8bcf15ba make colector hirarchicall
remove broken commit()
2017-02-12 13:39:39 +01:00
Christian Schabesberger
130757ee99 Update CONTRIBUTING.md 2017-02-12 00:16:41 +01:00
Christian Schabesberger
5020a4f9dc add mailinglist to contributing 2017-02-11 22:26:00 +01:00
Christian Schabesberger
ef15902ec4 add InfoItem 2017-02-11 21:33:01 +01:00
zmni
ed8d13f837 Translated using Weblate (Indonesian)
Currently translated at 100.0% (141 of 141 strings)
2017-02-11 19:20:01 +01:00
ksyko
c2fcae7c43 Merge pull request #1 from TeamNewPipe/master
0.8.9 update
2017-02-11 23:21:58 +05:30
aladar42
27f2c65e6d Translated using Weblate (Czech)
Currently translated at 100.0% (141 of 141 strings)
2017-02-10 18:44:38 +01:00
Weblate
0b3428ede9 Merge remote-tracking branch 'origin/master' 2017-02-08 17:13:21 +01:00
aladar42
3e0102ad2a Translated using Weblate (Czech)
Currently translated at 100.0% (141 of 141 strings)
2017-02-08 17:13:19 +01:00
Christian Schabesberger
c42002ccc5 removed download notice again 2017-02-06 00:04:20 +01:00
Christian Schabesberger
e8101d5d91 change download link 2017-02-05 23:56:26 +01:00
Christian Schabesberger
ecdf4ad502 add np download to readme 2017-02-05 21:09:36 +01:00
Matej U
af760f9cdc Translated using Weblate (Slovenian)
Currently translated at 100.0% (141 of 141 strings)
2017-02-05 20:16:33 +01:00
Weblate
b3491da49f Merge remote-tracking branch 'origin/master' 2017-02-05 12:46:26 +01:00
Snob Malkowitch
c322feeaff Translated using Weblate (Russian)
Currently translated at 94.3% (134 of 142 strings)
2017-02-05 12:46:18 +01:00
Christian Schabesberger
b26f46a063 Merge pull request #439 from marcobiscaro2112/master
Adding brazilian portuguese translation
2017-02-03 12:37:22 +01:00
Christian Schabesberger
9f0944dc5a Merge pull request #441 from k3b/master
fix NullPointerExcpeption when opening "Downloads" with android-api < 23
2017-02-03 12:35:52 +01:00
k3b
e869098434 fix NullPointerExcpeption when opening "Downloads" with android-api < 23 2017-02-02 01:58:47 +01:00
Weblate
4baa23af5f Merge remote-tracking branch 'origin/master' 2017-02-01 20:58:21 +01:00
aladar42
78fc5bbbd5 Translated using Weblate (Czech)
Currently translated at 97.1% (138 of 142 strings)
2017-02-01 20:58:20 +01:00
Wiredframe
a69784d168 Translated using Weblate (German)
Currently translated at 100.0% (142 of 142 strings)
2017-02-01 20:58:11 +01:00
Marco Biscaro
d48a7f1a18 Adding brazilian portuguese translation
(Also set settings_keys as untranslatable)
2017-02-01 12:32:06 -02:00
Christian Schabesberger
082c6128ad moved on to 0.8.9 2017-01-31 18:28:47 +01:00
Christian Schabesberger
7c9771873b Merge branch 'master' of git://github.com/ksyko/NewPipe into jf 2017-01-31 18:25:30 +01:00
Christian Schabesberger
7257cdacc8 fix background button problem 2017-01-31 18:23:22 +01:00
Christian Schabesberger
140b480f82 url signature fix
* fixed stacktrace
* changed player url
* took regex fix from youtube-dl

final fix taken from youtube-dl
2017-01-31 18:06:44 +01:00
Christian Schabesberger
77db2f8a48 update support Framework 2017-01-31 10:58:53 +01:00
naofum
22bc81b0eb Translated using Weblate (Japanese)
Currently translated at 100.0% (142 of 142 strings)
2017-01-27 15:50:44 +01:00
Mladen Pejaković
b52b3d4be0 Translated using Weblate (Serbian)
Currently translated at 100.0% (142 of 142 strings)
2017-01-26 18:49:26 +01:00
Nathan Follens
f845098b42 Translated using Weblate (Dutch)
Currently translated at 100.0% (142 of 142 strings)
2017-01-26 16:48:57 +01:00
Weblate
0f7397e3b8 Merge remote-tracking branch 'origin/master' 2017-01-26 15:46:09 +01:00
Shaye Faletha
0b9d99fdc9 Translated using Weblate (Polish)
Currently translated at 99.2% (140 of 141 strings)
2017-01-26 15:46:06 +01:00
59436419
9a1da5cc75 Made changes for ICS and JB 2017-01-26 12:07:41 +05:30
Christian Schabesberger
9e76f94cf6 update support lib and move on to 0.8.8 2017-01-22 14:47:05 +01:00
Christian Schabesberger
7d6b92e064 Merge branch 'feature-improve-search-fragment' of git://github.com/coffeemakr/NewPipe into cofe 2017-01-22 14:42:36 +01:00
Christian Schabesberger
849a45a3ca resolve conflict 2017-01-22 14:26:01 +01:00
Christian Schabesberger
7ddea5a71b Merge branch 'feature-accept-embed-links' of git://github.com/coffeemakr/NewPipe into url 2017-01-22 13:55:53 +01:00
Christian Schabesberger
5d81358c15 rename Themer to ThemableActivity 2017-01-22 13:48:50 +01:00
Christian Schabesberger
492aad9d70 Merge branch 'master' of git://github.com/ksyko/NewPipe into kyko 2017-01-22 13:32:39 +01:00
Weblate
647cfcd401 Merge remote-tracking branch 'origin/master' 2017-01-21 15:44:14 +01:00
Yann Hodiesne
c60d98e52d Translated using Weblate (French)
Currently translated at 97.1% (137 of 141 strings)
2017-01-21 15:44:14 +01:00
Osoitz
d3cfac6b15 Translated using Weblate (Basque)
Currently translated at 37.5% (53 of 141 strings)
2017-01-21 15:44:11 +01:00
Coffeemakr
7fb4e5a143 Rename download db sqlite file
Rename the sqlite database to "downloads.db" instead of "newpipe.db"
to make sure the file will create a conflicts later.
2017-01-20 18:57:30 +01:00
Coffeemakr
8e451b2a83 Use fragments setHasOptionsMenu
Remove complications by allowing android to handle fragment's
options menu.

See https://developer.android.com/guide/components/fragments.html#ActionBar
2017-01-19 19:39:33 +01:00
ksyko
8083f06fe7 Update SettingsFragment.java 2017-01-18 00:12:36 +05:30
59436419
44521a2e56 Added dark theme 2017-01-17 22:35:23 +05:30
59436419
dfeed3d0eb Added dark theme 2017-01-17 22:31:00 +05:30
59436419
081a45b70d Added dark theme 2017-01-17 22:13:33 +05:30
59436419
616a721bba Added dark theme 2017-01-17 21:43:30 +05:30
59436419
c9aa553b32 Added dark theme 2017-01-17 20:54:00 +05:30
59436419
e3d59c3cff Added dark theme 2017-01-17 20:47:12 +05:30
59436419
df51635674 Added dark theme 2017-01-17 20:33:54 +05:30
59436419
1e81f61760 Added dark theme 2017-01-17 20:31:14 +05:30
59436419
a4043eab83 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app/src/main/java/org/schabi/newpipe/Themer.java
#	app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
#	app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
#	app/src/main/res/layout-v18/fragment_videoitem_detail.xml
#	app/src/main/res/layout/fragment_videoitem_detail.xml
#	app/src/main/res/xml/settings.xml
2017-01-17 16:18:00 +05:30
59436419
60dc19d2bc Added Dark Theme 2017-01-17 16:13:14 +05:30
ksyko
a2e4585fe8 Update InfoItemHolder.java 2017-01-17 16:13:02 +05:30
ksyko
b5df281447 Update fragment_videoitem_detail.xml 2017-01-17 16:13:02 +05:30
ksyko
650917f9f9 Update fragment_videoitem_detail.xml 2017-01-17 16:13:02 +05:30
ksyko
3a9c95a9ae Update fragment_videoitem_detail.xml 2017-01-17 16:13:01 +05:30
59436419
5458acfcad Added dark theme 2017-01-17 16:13:01 +05:30
59436419
68e80e6054 Added dark theme 2017-01-17 16:13:01 +05:30
Christian Schabesberger
e4aa69b8d3 add some super.function() thingies 2017-01-16 16:06:54 +01:00
Coffeemakr
dfd40e43da Fix for #407 2017-01-16 13:01:52 +01:00
Coffeemakr
7efd111d9c Improve Search fragment
* Keep search query when fragment is restored
 * Simplify SuggestionListAdapter
   * Use ResourceCursorAdapter for view creation
 * Fix deprecation warning
 * Some clean code
2017-01-16 07:33:58 +01:00
Matej U
6809172203 Translated using Weblate (Slovenian)
Currently translated at 99.2% (140 of 141 strings)
2017-01-15 12:46:28 +01:00
Coffeemaker
40a4343f06 Translated using Weblate (German)
Currently translated at 98.5% (139 of 141 strings)
2017-01-13 18:45:02 +01:00
Matej U
cd9333b39e Translated using Weblate (Slovenian)
Currently translated at 98.5% (139 of 141 strings)
2017-01-12 21:46:19 +01:00
Mladen Pejaković
82d426c781 Translated using Weblate (Serbian)
Currently translated at 100.0% (141 of 141 strings)
2017-01-12 21:46:11 +01:00
YFdyh000
c7e773de25 Translated using Weblate (Chinese (Simplified))
Currently translated at 98.5% (139 of 141 strings)
2017-01-12 18:44:21 +01:00
Coffeemakr
2ded33110f Improve YoutubeStreamUrlIdHandler
* Make it a singelton
 * Accept embed links
 * Accept share links (youtube.com/shared?ci=...)
 * Add tests
 * Accept host case insensititve
2017-01-11 17:25:53 +01:00
zmni
b26c0aa9da Translated using Weblate (Indonesian)
Currently translated at 100.0% (141 of 141 strings)
2017-01-11 16:51:32 +01:00
Mladen Pejaković
2fc8fb6f17 Translated using Weblate (Serbian)
Currently translated at 100.0% (141 of 141 strings)
2017-01-10 21:08:24 +01:00
Coffeemakr
ea76f1d6e2 Improve DownloadManager and -Service
* Fix permission at some places
 * Fix access problem for downloaded files with external player
 * Store finished Downloads
 * Remove binding to DownloadService just to download a file
 * Javadoc
 * Code improvements
2017-01-10 17:48:55 +01:00
naofum
7cda1d116b Translated using Weblate (Japanese)
Currently translated at 100.0% (141 of 141 strings)
2017-01-10 17:03:28 +01:00
Weblate
8bf7a1a9db Merge remote-tracking branch 'origin/master' 2017-01-10 17:02:24 +01:00
naofum
0aa0ad65c0 Translated using Weblate (Japanese)
Currently translated at 100.0% (140 of 140 strings)
2017-01-10 17:02:21 +01:00
Coffeemakr
53ff58daa3 DownloadManagerService: Don't bind if no permissions 2017-01-10 13:35:16 +01:00
Christian Schabesberger
b3225bebe6 fix recaptch weblate conflict 2017-01-09 22:46:07 +01:00
Allan Nordhøy
4beafad71f Translated using Weblate (Norwegian Bokmål)
Currently translated at 92.8% (130 of 140 strings)
2017-01-09 21:45:13 +01:00
Allan Nordhøy
c96f933626 Translated using Weblate (English)
Currently translated at 100.0% (140 of 140 strings)
2017-01-09 21:45:12 +01:00
LNJ
bea6359d5f Translated using Weblate (German)
Currently translated at 99.2% (139 of 140 strings)
2017-01-09 21:45:04 +01:00
Christian Schabesberger
92db9cb59b update support lib and move on to 0.8.7 2017-01-04 17:20:01 +01:00
Benoît Mauduit
410c4ca736 Remove old comment 2017-01-03 14:38:22 +01:00
Benoît Mauduit
80c9dbf180 Cosmetic 2017-01-03 14:38:22 +01:00
Benoît Mauduit
c9edac2820 Change the way to start reCaptchaActivity
* Use startActivityForResult() and onActivityResult() to refresh the
  search request when returning from reCaptcha activity.
2017-01-03 14:38:22 +01:00
Benoît Mauduit
143df9a529 Start reCaptcha activity when starting video directly 2017-01-03 14:38:22 +01:00
Benoît Mauduit
c87da9903f Set result code and finish() Activity instead of starting MainActivity
* Activities will start reCaptchaActivity with startActivityForResult and
look for RECAPTCHA_REQUEST and RESULT_OK | RESULT_CANCELED in : 'onActivityResult()'
2017-01-03 14:38:22 +01:00
Andi Saputro
0f69e6c64d Translated using Weblate (Indonesian)
Currently translated at 100.0% (140 of 140 strings)
2016-12-31 18:45:16 +01:00
ksyko
1b9a6e53ce Update InfoItemHolder.java 2016-12-31 22:32:16 +05:30
ksyko
c7abf377eb Update fragment_videoitem_detail.xml 2016-12-31 21:51:41 +05:30
ksyko
175d8ce572 Update fragment_videoitem_detail.xml 2016-12-31 21:43:01 +05:30
ksyko
1708a401cf Update fragment_videoitem_detail.xml 2016-12-31 21:42:04 +05:30
59436419
141278e668 Added dark theme 2016-12-31 13:46:52 +05:30
59436419
754bd82699 Added dark theme 2016-12-30 01:07:27 +05:30
andideveloper
999efb6660 Translated using Weblate (Indonesian)
Currently translated at 100.0% (140 of 140 strings)
2016-12-29 17:25:23 +01:00
Weblate
0b391a9ef3 Merge remote-tracking branch 'origin/master' 2016-12-28 12:46:32 +01:00
naofum
2a99ac4430 Translated using Weblate (Japanese)
Currently translated at 100.0% (140 of 140 strings)
2016-12-28 12:46:22 +01:00
Christian Schabesberger
a5589d0865 Merge branch 'feature-background-progress' of git://github.com/coffeemakr/NewPipe into coffeemakr-feature-background-progress 2016-12-28 10:46:38 +01:00
Coffeemakr
83541a0d5d Add 8dp margin on the right side of the progress bar 2016-12-28 08:15:12 +01:00
Coffeemakr
ac0dff7aa1 Make shure thread quits before service 2016-12-27 16:17:59 +01:00
Coffeemakr
f22b5157f5 Notify thread on play/pause 2016-12-27 15:58:17 +01:00
Coffeemakr
659d0d6115 Add PlaybackState broadcast messages
They can be used to retrieve the current playback
 * Duration
 * Played time
 * If the media player is playing
2016-12-27 15:52:02 +01:00
Marian Hanzel
fd8c99fd8d Translated using Weblate (Slovak)
Currently translated at 100.0% (140 of 140 strings)
2016-12-27 15:47:58 +01:00
Coffeemakr
9494f3a299 Add progress bar to expanded notification 2016-12-27 14:49:59 +01:00
Coffeemakr
8021848b03 Remove note field completly
Always use noteBuilder directly to generate a notification
2016-12-27 14:41:30 +01:00
Coffeemakr
5a127c26e6 Improve notification building/updateing
* Use custom notification builder which has methods to set the artist
  and title and also a method to set the playing state
* Update builder instead of view -> resovles deprecated warnings
2016-12-27 14:37:18 +01:00
Coffeemakr
a7d734c20c Ignore vim's temporary files 2016-12-27 13:32:03 +01:00
Coffeemakr
7c7129f9a1 Notifications: Set customs views in builder 2016-12-27 13:31:34 +01:00
Coffeemakr
05cbc7891d Typos corrected in StreamInfo 2016-12-27 13:26:48 +01:00
Coffeemakr
14623456ff Correct typos 2016-12-27 13:19:12 +01:00
Coffeemakr
5064ec3ac4 Fix spelling 2016-12-27 13:16:51 +01:00
Gian Maria Viglianti
892888796d Translated using Weblate (Italian)
Currently translated at 100.0% (140 of 140 strings)
2016-12-26 14:57:31 +01:00
Weblate
4f2826d2c2 Merge remote-tracking branch 'origin/master' 2016-12-26 10:23:57 +01:00
YFdyh000
7f824d725b Translated using Weblate (Chinese (Simplified))
Currently translated at 98.5% (138 of 140 strings)
2016-12-26 10:23:56 +01:00
naofum
da4096c4ef Translated using Weblate (Japanese)
Currently translated at 100.0% (140 of 140 strings)
2016-12-26 10:23:55 +01:00
Christian Schabesberger
1aed11c156 change ip address provider
removed null bomb
2016-12-25 19:32:38 +01:00
Christian Schabesberger
e99e944ac3 make share with newpipe part of newpipe 2016-12-25 19:28:40 +01:00
Christian Schabesberger
6e523d37ba add copyright notice to DownloadListener 2016-12-25 15:24:37 +01:00
Christian Schabesberger
2aebf6b522 Merge branch 'master' of git://github.com/fr3ts0n/NewPipe into fr3ts0n-master 2016-12-25 15:20:31 +01:00
Mladen Pejaković
3f740980a3 Translated using Weblate (Serbian)
Currently translated at 100.0% (140 of 140 strings)
2016-12-25 14:16:58 +01:00
Weblate
66b73d1592 Merge remote-tracking branch 'origin/master' 2016-12-25 12:44:13 +01:00
RACER
be4b03b84b Translated using Weblate (Japanese)
Currently translated at 100.0% (138 of 138 strings)
2016-12-25 12:44:13 +01:00
Osoitz
3594037efe Translated using Weblate (Basque)
Currently translated at 34.0% (47 of 138 strings)
2016-12-25 12:44:11 +01:00
Christian Schabesberger
38c5cb50fb fixed Downloader.getInstance() in unit tests 2016-12-24 17:11:29 +01:00
Christian Schabesberger
3767a96e0f moved on to version 0.8.6 2016-12-24 16:06:24 +01:00
Christian Schabesberger
937a387f4e rename reCaptchaException to ReCaptchaException 2016-12-24 15:19:40 +01:00
Christian Schabesberger
cd65f1dffc Merge branch 'reCaptcha' of git://github.com/be-neth/NewPipe into be-neth-reCaptcha 2016-12-24 14:13:12 +01:00
Christian Schabesberger
d4e6856cbe Merge pull request #394 from ngoisaosang/master
Try to fix accept SDK Licenses
2016-12-24 14:12:36 +01:00
ngoisaosang
f61d779108 Try to fix travis 2016-12-24 07:25:27 +07:00
ngoisaosang
b8b22d4d91 Fix travis 2016-12-23 13:47:20 +07:00
ngoisaosang
25d0e39736 Update gradle 2016-12-22 22:45:42 +07:00
ngoisaosang
79a9497e65 Fix travis build 2016-12-22 17:40:01 +07:00
Christian Schabesberger
c55dcccb1e Merge branch 'fix-channel-bannel-url' of git://github.com/coffeemakr/NewPipe into coffeemakr-fix-channel-bannel-url 2016-12-21 21:01:47 +01:00
Christian Schabesberger
820e606719 fix duration_background name 2016-12-21 21:00:05 +01:00
Christian Schabesberger
96291a8522 Merge branch 'coffeemakr-fix-yt-dublicated-result-page' 2016-12-21 20:56:40 +01:00
Christian Schabesberger
e7b52bd3b0 Merge pull request #392 from ksyko/patch-1
Fixes spelling
2016-12-21 20:42:03 +01:00
ksyko
dd3251c08d Fixes spelling 2016-12-21 20:38:51 +05:30
Coffeemakr
f4aabdd9b8 Accept SDK Licenses 2016-12-19 19:40:28 +01:00
Coffeemakr
cb1fe5f017 Try to fix travis 2016-12-19 19:36:24 +01:00
Coffeemakr
83837bde11 Google begins with page 1 so we add 1 to our page starting with 0 2016-12-19 19:28:16 +01:00
Coffeemakr
05189dadbf Fix banner extaction 2016-12-19 13:32:03 +01:00
Selim
dbb1f371b3 Translated using Weblate (Turkish)
Currently translated at 94.2% (130 of 138 strings)
2016-12-13 21:46:13 +01:00
Benoît Mauduit
5cc1bbc4bb Add missing Override decorator 2016-12-07 22:26:54 +01:00
Benoît Mauduit
53796043c3 Start reCaptchaActivity when reCaptcha is requested and fix Typo
* Fix typo setSearchWorkerResultListner to setSearchWorkerResultListener
2016-12-07 22:26:54 +01:00
Benoît Mauduit
a5ac528c02 Add reCaptchaException 2016-12-07 22:26:54 +01:00
Benoît Mauduit
54eb353d0d Add ReCaptcha Activity
* ReCaptchas are implemented using a simple WebView with Javascript enable.

 * All HTTP responses inside the WebView are catched (using onPageFinished())
 ** When Google reCatcha cookies are detected, register cookies to the
    Downloader class and Return to MainActivity
2016-12-07 22:26:54 +01:00
Benoît Mauduit
3391067cab Adding cookies member to Downloader 2016-12-07 22:26:54 +01:00
Benoît Mauduit
b4f595eb75 Make Downloader class a Singleton 2016-12-07 22:26:54 +01:00
Weblate
58bc0c17d0 Merge remote-tracking branch 'origin/master' 2016-12-02 10:24:55 +01:00
Cyxae Dexyc
4385404ad6 Translated using Weblate (French)
Currently translated at 98.5% (136 of 138 strings)
2016-12-02 10:24:54 +01:00
Marian Hanzel
61aadcffd2 Translated using Weblate (Slovak)
Currently translated at 100.0% (138 of 138 strings)
2016-12-02 10:24:52 +01:00
Christian Schabesberger
f575826394 fix unit tests 2016-11-20 19:01:06 +01:00
Christian Schabesberger
389959dd18 Merge pull request #366 from coffeemakr/delete-swiss-high-german
Delete Swiss High German translation
2016-11-20 15:43:37 +01:00
Christian Schabesberger
af4734eee3 update to sdk version 25 2016-11-18 23:56:08 +01:00
Christian Schabesberger
f76b37ec39 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2016-11-18 23:52:34 +01:00
Christian Schabesberger
379149fe2f update unit tests so it works with current updates 2016-11-18 23:52:17 +01:00
Christian Schabesberger
3bd477631c fixed spelling error 2016-11-18 22:08:53 +01:00
Freddy Morán Jr
72c0987bad Translated using Weblate (Spanish)
Currently translated at 100.0% (138 of 138 strings)
2016-11-10 03:46:02 +01:00
fr3ts0n
5bba8e02a6 add media scanner notification after successful download 2016-11-06 21:08:57 +01:00
Freddy Morán Jr
b270de3335 Translated using Weblate (Spanish)
Currently translated at 100.0% (138 of 138 strings)
2016-11-03 21:46:25 +01:00
Freddy Morán Jr
e22bcf0ac5 Translated using Weblate (Serbian)
Currently translated at 100.0% (138 of 138 strings)
2016-11-03 21:46:13 +01:00
Freddy Morán Jr
c1d55d828f Translated using Weblate (Portuguese)
Currently translated at 100.0% (138 of 138 strings)
2016-11-03 21:45:51 +01:00
Freddy Morán Jr
da77970328 Translated using Weblate (Indonesian)
Currently translated at 100.0% (138 of 138 strings)
2016-11-03 21:45:12 +01:00
Freddy Morán Jr
32f3caaee0 Translated using Weblate (German)
Currently translated at 100.0% (138 of 138 strings)
2016-11-03 21:44:57 +01:00
Дима Гайнуллин
8bbacb1d78 Translated using Weblate (Russian)
Currently translated at 88.4% (122 of 138 strings)
2016-11-03 18:45:52 +01:00
Nathan Follens
5904510410 Translated using Weblate (Dutch)
Currently translated at 100.0% (138 of 138 strings)
2016-10-30 00:44:27 +02:00
Enol P
e16624251b Translated using Weblate (Asturian)
Currently translated at 97.1% (134 of 138 strings)
2016-10-21 03:44:09 +02:00
zmni
389f22a0e5 Translated using Weblate (Indonesian)
Currently translated at 99.2% (137 of 138 strings)
2016-10-16 12:45:00 +02:00
zmni
7b91aa16b6 Translated using Weblate (Indonesian)
Currently translated at 95.6% (132 of 138 strings)
2016-10-13 21:45:17 +02:00
Jona Abdinghoff
89ec688632 Translated using Weblate (German)
Currently translated at 99.2% (137 of 138 strings)
2016-10-12 00:44:52 +02:00
Nathan Follens
fdd0d586c9 Translated using Weblate (Dutch)
Currently translated at 99.2% (137 of 138 strings)
2016-10-12 00:44:25 +02:00
Coffeemakr
6f5604791f Delete swiss high german 2016-10-11 07:30:18 +02:00
Gian Maria Viglianti
eb9fba4147 Translated using Weblate (Italian)
Currently translated at 100.0% (138 of 138 strings)
2016-10-10 18:45:06 +02:00
Weblate
afb62f729f Merge remote-tracking branch 'origin/master' 2016-10-04 15:45:09 +02:00
Nathan Follens
1ccc23dc9c Translated using Weblate (Dutch)
Currently translated at 68.8% (95 of 138 strings)
2016-10-04 15:45:07 +02:00
intrnl
7ea5cb9c5c Translated using Weblate (Indonesian)
Currently translated at 37.6% (52 of 138 strings)
2016-10-04 15:44:59 +02:00
Christian Schabesberger
c301d6e5d5 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2016-10-01 23:22:18 +02:00
naofum
44ad69b94d Translated using Weblate (Japanese)
Currently translated at 100.0% (138 of 138 strings)
2016-10-01 18:45:10 +02:00
Christian Schabesberger
d14515ab88 Merge remote-tracking branch 'origin/master' 2016-09-28 17:13:23 +02:00
Christian Schabesberger
01875b389d clean up extractor 2016-09-28 17:13:15 +02:00
Christian Schabesberger
5eef116aaa put Suggestion extraction into its own class 2016-09-28 12:53:23 +02:00
Weblate
442220debc Merge remote-tracking branch 'origin/master' 2016-09-28 12:45:55 +02:00
kamadi
4914caad51 Translated using Weblate (Russian)
Currently translated at 48.5% (67 of 138 strings)
2016-09-28 12:45:54 +02:00
Gian Maria Viglianti
08cab863f1 Translated using Weblate (Italian)
Currently translated at 98.5% (136 of 138 strings)
2016-09-28 12:45:54 +02:00
Marian Hanzel
02458d4fc1 Translated using Weblate (Slovak)
Currently translated at 98.5% (136 of 138 strings)
2016-09-28 12:45:51 +02:00
Christian Schabesberger
6ed4130b66 fix collisions 2016-09-28 11:54:35 +02:00
Felix Ableitner
5f7ee15d1e Launch video player in single task mode (fixes #154) 2016-09-28 13:09:42 +09:00
Christian Schabesberger
43afd5a2b8 clean up downloader thing 2016-09-27 22:59:04 +02:00
Christian Schabesberger
f9ac199c1f fixed .webm download locatiion issue 2016-09-27 21:33:26 +02:00
Christian Schabesberger
920c169d55 update CI batch in README 2016-09-27 20:22:01 +02:00
Christian Schabesberger
76ba2824a2 stability improvements 2016-09-27 20:18:41 +02:00
Christian Schabesberger
ca0d594547 cleaning away android stuff from extractor 2016-09-27 20:06:33 +02:00
Christian Schabesberger
44b6d900f0 Merge branch 'master' of github.com:TeamNewPipe/NewPipe 2016-09-27 14:58:54 +02:00
Christian Schabesberger
3b2c0186aa update issue teamplate 2016-09-27 14:58:46 +02:00
Christian Schabesberger
efa605700d update contributions link in the readme 2016-09-27 14:33:30 +02:00
Christian Schabesberger
cac360d37b add .github folder 2016-09-27 14:30:03 +02:00
Christian Schabesberger
75e28893fb update contribution guidelines once again 2016-09-27 14:14:59 +02:00
Christian Schabesberger
360a44b5a0 update contribution guidelines 2016-09-27 13:43:43 +02:00
Christian Schabesberger
2b89e24a4b make download dialog use radio button 2016-09-26 20:18:32 +02:00
Christian Schabesberger
931f34d2fd fixed related videos nullpointer exception 2016-09-26 18:01:39 +02:00
Christian Schabesberger
abfdcea4db moved on to 0.8.5 2016-09-26 17:32:03 +02:00
Christian Schabesberger
80b3b8ac0f change readme layout 2016-09-26 17:04:54 +02:00
Christian Schabesberger
60e18aa045 similar videos scroll bug workaround 2016-09-26 17:02:55 +02:00
Christian Schabesberger
85e2b124ab Merge branch 'master' of github.com:theScrabi/NewPipe 2016-09-25 21:22:37 +02:00
Christian Schabesberger
81a8cd0641 update to gradle2.2.0 2016-09-25 21:22:29 +02:00
Weblate
303805755d Merge remote-tracking branch 'origin/master' 2016-09-25 19:23:20 +02:00
Gian Maria Viglianti
38837d6424 Translated using Weblate (Italian)
Currently translated at 97.1% (134 of 138 strings)
2016-09-25 19:23:19 +02:00
Christian Schabesberger
8a582c2a24 fix weblate merge conflict 2016-09-25 19:23:10 +02:00
Tiago Roque Medeiros
5cfb65002d Translated using Weblate (Portuguese)
Currently translated at 99.2% (137 of 138 strings)
2016-09-22 18:45:35 +02:00
Benedikt Freisen
fa6dee45ec Translated using Weblate (German)
Currently translated at 98.5% (136 of 138 strings)
2016-09-20 16:56:29 +02:00
Sérgio Marques
af25fe93da Translated using Weblate (Portuguese)
Currently translated at 99.2% (137 of 138 strings)
2016-09-20 16:56:28 +02:00
naofum
395ad3e8ef Translated using Weblate (Japanese)
Currently translated at 99.2% (137 of 138 strings)
2016-09-18 09:45:36 +02:00
marxsouza12
2cbaca8968 Translated using Weblate (Portuguese)
Currently translated at 97.1% (134 of 138 strings)
2016-09-18 09:45:34 +02:00
Christian Schabesberger
bf90788e04 update featurs at readme
update featurs at readme once again
2016-09-15 10:35:22 +02:00
Christian Schabesberger
83ffb849cd update featurs at readme 2016-09-15 10:31:48 +02:00
Christian Schabesberger
a34a33e419 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-09-14 18:35:22 +02:00
Christian Schabesberger
57f620485f fix ui crash bug 2016-09-14 18:35:17 +02:00
Weblate
18cdde963b Merge remote-tracking branch 'origin/master' 2016-09-14 15:45:35 +02:00
Mladen Pejaković
6c1f472de3 Translated using Weblate (Serbian)
Currently translated at 99.2% (137 of 138 strings)
2016-09-14 15:45:35 +02:00
Christian Schabesberger
efd2ac353e fix WORLD_MODE_READABLE bug
blub
2016-09-14 11:29:40 +02:00
Christian Schabesberger
863bf9dc8b fix channel has no second page bug 2016-09-14 11:15:08 +02:00
Weblate
fd411c17cd Merge remote-tracking branch 'origin/master' 2016-09-14 00:50:31 +02:00
YFdyh000
5424c23d69 Translated using Weblate (Simplified Chinese)
Currently translated at 97.8% (135 of 138 strings)
2016-09-14 00:50:31 +02:00
Christian Schabesberger
b8a0801786 fixed bug regarding channels
acual fix
2016-09-14 00:50:18 +02:00
Christian Schabesberger
39ff1cd898 Merge pull request #357 from theScrabi/ref_crashreport
Refactore crashreport
2016-09-14 00:05:37 +02:00
Christian Schabesberger
a2a3b0575d gather all bug shit things 2016-09-13 23:39:32 +02:00
Christian Schabesberger
2b8954353d removed crash test line 2016-09-13 23:31:28 +02:00
Christian Schabesberger
9bd5aa0da4 add package field to crash report 2016-09-13 23:31:06 +02:00
Christian Schabesberger
af2cddee91 made acra catch and report errors 2016-09-13 23:24:49 +02:00
Christian Schabesberger
27bc414616 add copyright notice 2016-09-13 22:38:45 +02:00
Christian Schabesberger
14eaedd73a use intent system to pass errors to error activity 2016-09-13 22:36:47 +02:00
Christian Schabesberger
a2effef346 fix build tooles for CI 2016-09-13 00:21:02 +02:00
Christian Schabesberger
caf938f79f add channel extractor tests 2016-09-12 23:44:57 +02:00
Christian Schabesberger
8ececc11d2 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-09-12 23:07:31 +02:00
Christian Schabesberger
cf1d546683 add new play icon 2016-09-12 23:07:23 +02:00
Weblate
e8144f4906 Merge remote-tracking branch 'origin/master' 2016-09-12 22:35:28 +02:00
naofum
bfb6f14769 Translated using Weblate (Japanese)
Currently translated at 99.2% (136 of 137 strings)
2016-09-12 22:35:27 +02:00
Christian Schabesberger
ff1ba2b5bf Merge branch 'master' of github.com:theScrabi/NewPipe 2016-09-12 22:35:15 +02:00
Christian Schabesberger
8c26f29f94 shitty fix for detail progressbar 2016-09-12 17:49:49 +02:00
Weblate
bdd57f3b3e Merge remote-tracking branch 'origin/master' 2016-09-12 16:22:16 +02:00
YFdyh000
e09bf4d09c Translated using Weblate (Simplified Chinese)
Currently translated at 98.5% (135 of 137 strings)
2016-09-12 16:22:16 +02:00
Christian Schabesberger
e0dbf4c2cd fix settings updateSummary 2016-09-12 16:22:02 +02:00
Christian Schabesberger
4bba84af8a Merge pull request #316 from jaytj95/master
Added rewind capability to notification control
2016-09-12 00:57:53 +02:00
Christian Schabesberger
bd7077c1cf fix rising exception for empty related videos 2016-09-12 00:56:20 +02:00
Christian Schabesberger
a63128bd45 add addblock 2016-09-12 00:51:03 +02:00
Christian Schabesberger
6944f4a68a add copyright headers and update sdk 2016-09-12 00:33:11 +02:00
Christian Schabesberger
54ab0ab17e fix merge with add_cahnnels 2016-09-12 00:12:00 +02:00
Christian Schabesberger
2080bb2da1 Merge pull request #350 from KeizerDev/splash-screen
Added Splash Screen to bypass blank screen on start up.
2016-09-11 23:57:30 +02:00
Christian Schabesberger
cc74c98509 add bugrepport to channel acitivty 2016-09-11 23:15:22 +02:00
Christian Schabesberger
dd6c6ae03f seems to made it working 2016-09-10 18:47:35 +02:00
Christian Schabesberger
4f8ca9ef16 fucking brought it almost to work fuck 2016-09-10 18:28:48 +02:00
Christian Schabesberger
53059bcb91 level 1 of making loading more content work 2016-09-10 16:26:21 +02:00
Filip Sebastian
cb056f4f80 Translated using Weblate (Romanian)
Currently translated at 100.0% (133 of 133 strings)
2016-08-24 12:45:40 +02:00
Robert-Jan Keizer
05bfa8b85e Added splash screen to bypass blank screen on start up. 2016-08-22 01:13:09 +02:00
Christian Schabesberger
6dc5350c43 update gradle and fix load image error string 2016-08-20 00:56:10 +02:00
Enol P
5cdf807d92 Translated using Weblate (Asturian)
Currently translated at 100.0% (133 of 133 strings)
2016-08-18 06:44:10 +02:00
Enol P
9c2a9e64c2 Translated using Weblate (Asturian)
Currently translated at 100.0% (133 of 133 strings)
2016-08-16 03:43:01 +02:00
Enol P
3b60b801c2 Added translation using Weblate (Asturian) 2016-08-16 02:38:40 +02:00
Danial Behzadi
c78eb80686 Translated using Weblate (Persian)
Currently translated at 100.0% (133 of 133 strings)
2016-08-12 15:45:23 +02:00
Danial Behzadi
9b9da648c9 Translated using Weblate (Persian)
Currently translated at 100.0% (133 of 133 strings)
2016-08-10 15:33:17 +02:00
Danial Behzadi
adc2b9c43a Added translation using Weblate (Persian) 2016-08-10 14:21:05 +02:00
Weblate
b3954e9acd Merge remote-tracking branch 'origin/master' 2016-08-08 22:05:14 +02:00
Christian Schabesberger
6e36f0ef83 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-08-08 22:11:40 +02:00
Christian Schabesberger
64afb907e6 change icon 2016-08-08 22:11:32 +02:00
Rom1
3552125075 Translated using Weblate (French)
Currently translated at 100.0% (133 of 133 strings)
2016-08-08 22:05:13 +02:00
Christian Schabesberger
2601bf6d81 change view naming in detail fragment 2016-08-08 20:21:18 +02:00
David
3da032b7ee Update filepicker to the newest version and Fix for #343 2016-08-03 18:36:46 -03:00
Christian Schabesberger
7bea94144e fix search fragment progressbar 2016-08-03 17:18:05 +02:00
Dawid
40b08a593f Translated using Weblate (Polish)
Currently translated at 95.4% (127 of 133 strings)
2016-08-03 15:45:26 +02:00
Christian Schabesberger
5d06e8310d animate item button and made channel layout use recyclerview propper 2016-08-03 15:32:25 +02:00
Christian Schabesberger
1ab82dfa32 made channel activity use recycler view 2016-08-03 13:09:48 +02:00
Sérgio Marques
b93372926a Translated using Weblate (Portuguese)
Currently translated at 100.0% (133 of 133 strings)
2016-08-03 12:45:28 +02:00
Christian Schabesberger
557bcc40ef made detail fragment use recycler view 2016-08-03 00:54:03 +02:00
Christian Schabesberger
06e2e548be restructure detail activity 2016-08-03 00:12:58 +02:00
Christian Schabesberger
7a25588995 remove listactivity layout 2016-08-02 21:30:55 +02:00
Christian Schabesberger
8107337566 restructure ui 2016-08-02 21:17:54 +02:00
Christian Schabesberger
d6de11f54c remove video item list plemp 2016-08-02 20:59:53 +02:00
Christian Schabesberger
2f2334eac4 make search fagment handle video items 2016-08-02 18:38:05 +02:00
Christian Schabesberger
3a5b9203d8 put search fragment into own package 2016-08-02 15:06:02 +02:00
Christian Schabesberger
c46ce1170c add search fragment 2016-08-02 01:42:05 +02:00
Christian Schabesberger
1170c508b4 add new architecture 2016-08-02 01:26:12 +02:00
Christian Schabesberger
f34cacbc5c add recycler view adapter 2016-08-02 00:58:52 +02:00
Christian Schabesberger
4164195fae show channelvideos 2016-08-01 21:50:41 +02:00
Christian Schabesberger
c03b106118 add channel avatar 2016-08-01 11:48:52 +02:00
Dawid
c760a4e0ef Added translation using Weblate (Polish) 2016-08-01 09:28:48 +02:00
Christian Schabesberger
f3a73ecc4a add feed function 2016-08-01 02:10:38 +02:00
Christian Schabesberger
6beb36f92f get channel banner 2016-08-01 01:56:19 +02:00
Christian Schabesberger
033a4ecbe8 add now (actual) logo 2016-07-31 17:23:46 +02:00
Sérgio Marques
6360d61721 Translated using Weblate (Portuguese)
Currently translated at 100.0% (133 of 133 strings)
2016-07-31 16:20:39 +02:00
Christian Schabesberger
5dd3f6cd02 add new logo to assets 2016-07-31 14:40:19 +02:00
Utku BERBEROĞLU
cb3c595d2b Translated using Weblate (Turkish)
Currently translated at 34.5% (46 of 133 strings)
2016-07-30 18:46:18 +02:00
Marian Hanzel
f4414851be Translated using Weblate (Slovak)
Currently translated at 100.0% (133 of 133 strings)
2016-07-27 10:01:18 +02:00
Christian Schabesberger
9a0f61e60b add basics 2016-07-26 13:50:52 +02:00
naofum
22fc690c65 Translated using Weblate (Japanese)
Currently translated at 100.0% (133 of 133 strings)
2016-07-25 13:23:40 +02:00
Christian Schabesberger
c5583bd77b try to fix failing CI 2016-07-25 12:28:00 +02:00
Christian Schabesberger
8fbee92255 try to fix failing CI 2016-07-25 12:11:55 +02:00
Christian Schabesberger
1fd6685b3b removed orebot/tor support 2016-07-25 11:59:37 +02:00
Christian Schabesberger
e6fe1d2008 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-07-25 11:13:04 +02:00
Christian Schabesberger
c0ce14dba5 moved on to new sdk, and put settings activity result into its fragment 2016-07-25 11:12:54 +02:00
YFdyh000
9f315fb021 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (133 of 133 strings)
2016-07-25 03:56:47 +02:00
Christian Schabesberger
dc46b3f6c0 Merge pull request #314 from satiricon/pref-filepicker
File picker for download preferences.
2016-07-25 00:48:48 +02:00
Christian Schabesberger
24dd94fba3 Merge pull request #317 from ggppjj/master
Change "click" to "tap".
2016-07-25 00:46:49 +02:00
Christian Schabesberger
d3d4e8c721 Merge pull request #321 from DevFactory/release/collection-interfaces-should-be-used-fix-1
Code quality fix - Declarations should use Java collection interfaces such as "List" rather than specific implementation.
2016-07-25 00:46:33 +02:00
Nigel
990d3fc714 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 97.7% (130 of 133 strings)
2016-07-24 12:44:17 +02:00
Christian Schabesberger
9c82f0b12a moved to sdk version 24 2016-07-21 16:43:24 +02:00
Christian Schabesberger
47bdd2e565 Merge pull request #331 from Gracecr/patch-1
Allow for large times stamps fixing #330
2016-07-21 07:15:13 +02:00
David
9a5e82cb1e Updating code to make it compatible with master 2016-07-19 16:56:53 -03:00
David
2ab9db3c07 A little cleanup 2016-07-19 16:53:20 -03:00
David
b3fdd2b0cb Done with the file picker for the download settings 2016-07-19 16:53:20 -03:00
David
bd43efd2c2 The file picker is working and I'm reordering the code to make it easier to follow 2016-07-19 16:52:37 -03:00
David
36babcaf36 Trying to make last filepicker version work, maybe I'm having some memory problems 2016-07-19 16:51:14 -03:00
David
45be3fb0e8 Starting to add a filepicker to the directory preferences 2016-07-19 16:51:14 -03:00
Gracecr
c880047c4f Allows for large times stamps fixing #330
@scde submitted #330, along with a couple proposed fixes.
This is the second proposed fix, which allows for arbitrarily large
timestamps. All credit to @scde for this.
2016-07-14 16:50:57 -04:00
Christian Schabesberger
66e88829dd Merge pull request #327 from adelolmo/master
fix build. remove wrong xliff namespaces from spanish translation.
2016-07-04 17:46:52 +02:00
Andoni del Olmo
3add3d75a1 skip ads and channels from test. 2016-07-04 12:05:43 +02:00
Andoni del Olmo
8644a4542a skip ads and channels from test. 2016-07-04 11:43:18 +02:00
andoni
0b6bae6ce3 change test search term to avoid google ads. 2016-07-03 16:25:32 +02:00
Faisal Hameed
13346ab750 Fixing squid:S1319 - Declarations should use Java collection interfaces such as "List" rather than specific implementation. 2016-07-01 04:05:55 +05:00
andoni
f65c08431c support all variants of vnd.youtube url. 2016-06-30 20:21:54 +02:00
andoni
4cde97e65d fix build. remove wrong xliff namespaces from spanish translation. 2016-06-30 20:14:27 +02:00
Christian Schabesberger
049b36b1b6 Merge pull request #323 from DevFactory/release/public-static-fields-should-be-constants-fix-1
Code quality fix - "public static" fields should be constant.
2016-06-30 16:57:42 +02:00
Christian Schabesberger
faed0958b3 Merge pull request #322 from DevFactory/release/string-literals-should-not-be-duplicated-fix-1
Code quality fix - String literals should not be duplicated.
2016-06-30 16:56:41 +02:00
Christian Schabesberger
3b36b7f01b Merge pull request #324 from DevFactory/release/redundant-modifiers-should-not-be-used-fix-1
Code quality fix - Redundant modifiers should not be used.
2016-06-30 16:56:11 +02:00
Weblate
5a2b236e71 Merge remote-tracking branch 'origin/master' 2016-06-30 16:55:41 +02:00
Riccardo Boninsegna
e5db08b0a8 Translated using Weblate (Italian)
Currently translated at 100.0% (133 of 133 strings)
2016-06-30 16:55:41 +02:00
Coffeemaker
e29eeb5d3d Translated using Weblate (German)
Currently translated at 96.2% (128 of 133 strings)
2016-06-30 16:55:41 +02:00
Christian Schabesberger
6dac88c394 Merge pull request #325 from DevFactory/release/redundant-field-initializers-fix-1
Code quality fix - Redundant Field Initializer.
2016-06-30 16:55:35 +02:00
Riccardo Boninsegna
580a0069dc Translated using Weblate (Italian)
Currently translated at 100.0% (133 of 133 strings)
2016-06-29 22:28:04 +02:00
Coffeemaker
187d65ffa5 Added translation using Weblate (Swiss High German) 2016-06-29 18:54:53 +02:00
Christian Schabesberger
7b0ef1824f add warning to nod add newpipe to playstore 2016-06-28 22:37:24 +02:00
Faisal Hameed
404017cba3 Fixing squid:S1192 - String literals should not be duplicated. 2016-06-24 14:54:18 +05:00
Faisal Hameed
dd2398efad Fixing pmd:RedundantFieldInitializer - Redundant Field Initializer. 2016-06-24 05:44:42 +05:00
Faisal Hameed
a44518a757 Fixing squid:S2333 - Redundant modifiers should not be used. 2016-06-24 05:44:09 +05:00
Faisal Hameed
83eb83025a Fixing squid:S1444 - "public static" fields should be constant. 2016-06-24 05:30:46 +05:00
Gabriel Jones
464a113f11 Change "click" to "tap". 2016-06-23 11:41:01 -04:00
Weblate
25a776cc93 Merge remote-tracking branch 'origin/master' 2016-06-22 23:41:13 +02:00
Rom1
7d19fb878d Translated using Weblate (French)
Currently translated at 100.0% (133 of 133 strings)
2016-06-22 23:41:12 +02:00
Christian Schabesberger
f5aef6879a Update CONTRIBUTING.md
fixed broken slack link
2016-06-22 23:41:09 +02:00
hatsunearu
29014d7b4a Translated using Weblate (Korean)
Currently translated at 85.7% (114 of 133 strings)
2016-06-22 09:45:15 +02:00
hd hd
9668a78732 Translated using Weblate (Hungarian)
Currently translated at 100.0% (133 of 133 strings)
2016-06-22 03:44:49 +02:00
devnoname120
a1aafb17c9 Translated using Weblate (French)
Currently translated at 100.0% (133 of 133 strings)

Not literally translated because used here: ddc3b47dfa/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java (L182)
2016-06-22 00:44:36 +02:00
Murat Dikici
9883678fd9 Translated using Weblate (Turkish)
Currently translated at 17.2% (23 of 133 strings)
2016-06-20 09:45:49 +02:00
hd hd
ba72379aa9 Translated using Weblate (Hungarian)
Currently translated at 100.0% (133 of 133 strings)
2016-06-20 00:58:09 +02:00
devnoname120
3206fef865 Translated using Weblate (French)
Currently translated at 81.2% (108 of 133 strings)
2016-06-19 22:55:25 +02:00
Freddy Morán Jr
06b6216b9d Translated using Weblate (Spanish)
Currently translated at 100.0% (133 of 133 strings)
2016-06-18 21:45:48 +02:00
Marian Hanzel
5458606abe Translated using Weblate (Slovak)
Currently translated at 100.0% (133 of 133 strings)
2016-06-18 12:35:17 +02:00
Murat Dikici
ad5cf99d9e Added translation using Weblate (Turkish) 2016-06-18 08:40:56 +02:00
Freddy Morán Jr
0445086e67 Translated using Weblate (Spanish)
Currently translated at 100.0% (133 of 133 strings)
2016-06-16 15:11:35 +02:00
Jason John
51641dcc9a Added rewind capability to notification control ( seekTo(0) ) 2016-06-16 09:11:18 -04:00
David
d1e698185e A little cleanup 2016-06-16 07:58:09 -03:00
David
d145a3e967 Done with the file picker for the download settings 2016-06-15 12:56:03 -03:00
David
4a5190292c The file picker is working and I'm reordering the code to make it easier to follow 2016-06-15 12:56:03 -03:00
David
1b7cece306 Trying to make last filepicker version work, maybe I'm having some memory problems 2016-06-15 12:55:37 -03:00
David
181c83090d Starting to add a filepicker to the directory preferences 2016-06-15 12:53:02 -03:00
Christian Schabesberger
54c32b9fe2 moved on to version 0.8.0:
* moved on to version 0.8.0
* removed posibility to use *.jar files
* updated dependend libraries
2016-06-12 18:24:16 +02:00
David
9d5951765f Fix for #310 2016-06-08 12:35:54 -03:00
David
ddc3b47dfa Fix for #308 part 2 2016-06-07 11:43:13 -03:00
David
59523d6a08 Fix for #308 2016-06-07 11:32:31 -03:00
Christian Schabesberger
686f395158 Merge pull request #307 from mingchen/master
Upgrade gradle wrapper to 2.10 and fix compile errors.
2016-06-04 10:54:12 +02:00
Ming Chen
f7b7340b30 Fix compile error due to improper define of xmlns 2016-06-03 16:13:30 -07:00
Ming Chen
9bcdad0218 Upgrade wrapper to 2.10 2016-06-03 15:53:02 -07:00
Matej U
ff4601f487 Translated using Weblate (Slovenian)
Currently translated at 100.0% (133 of 133 strings)
2016-06-03 10:49:16 +02:00
Renan Souza do Nascimento
535cebde51 Translated using Weblate (Portuguese)
Currently translated at 99.2% (132 of 133 strings)
2016-05-31 00:45:17 +02:00
Weblate
ed23faa455 Merge remote-tracking branch 'origin/master' 2016-05-27 15:29:12 +02:00
naofum
0c695d721d Translated using Weblate (Japanese)
Currently translated at 100.0% (133 of 133 strings)
2016-05-27 15:29:12 +02:00
Benedikt Freisen
d7a208dcee Translated using Weblate (German)
Currently translated at 91.7% (122 of 133 strings)
2016-05-27 15:29:11 +02:00
Christian Schabesberger
3eb2a26e4e blub commit 2016-05-27 15:29:02 +02:00
Mladen Pejaković
cc2d365e5a Translated using Weblate (Serbian)
Currently translated at 100.0% (133 of 133 strings)
2016-05-26 22:41:03 +02:00
naofum
76ac2cc58e Translated using Weblate (Japanese)
Currently translated at 100.0% (133 of 133 strings)
2016-05-26 12:44:04 +02:00
Christian Schabesberger
aee26fcffc add downloads menu item to detail fragment 2016-05-26 00:11:42 +02:00
Christian Schabesberger
685eebeb56 add title to activitys 2016-05-25 23:51:22 +02:00
Christian Schabesberger
f23ae091cc add icons for progress tiles 2016-05-25 23:35:27 +02:00
Christian Schabesberger
1421dca35f clean up gigaget code 2016-05-25 23:08:15 +02:00
Christian Schabesberger
39c2f31a22 changed color of download blocks 2016-05-25 22:59:32 +02:00
Christian Schabesberger
239ef1c238 add action for downloads menu item 2016-05-25 22:34:36 +02:00
Christian Schabesberger
466ba93750 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-05-25 22:19:47 +02:00
Marian Hanzel
72007a0162 Translated using Weblate (Slovak)
Currently translated at 100.0% (129 of 129 strings)
2016-05-25 19:50:47 +02:00
David
26c0445b83 Fix for #273 2016-05-25 08:27:15 -03:00
Christian Schabesberger
6f6c1704d4 add downloads menu item 2016-05-24 14:06:49 +02:00
Weblate
14aa6de422 Merge remote-tracking branch 'origin/master' 2016-05-24 13:51:33 +02:00
Mladen Pejaković
eeb770ffe3 Translated using Weblate (Serbian)
Currently translated at 100.0% (129 of 129 strings)
2016-05-24 13:51:33 +02:00
David
382ac3470b Fix for #298 2016-05-24 08:51:08 -03:00
naofum
3abfb08090 Translated using Weblate (Japanese)
Currently translated at 100.0% (129 of 129 strings)
2016-05-23 13:24:57 +02:00
Matej U
b4aac839c9 Translated using Weblate (Slovenian)
Currently translated at 100.0% (129 of 129 strings)
2016-05-22 22:29:22 +02:00
YFdyh000
da984c23df Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (129 of 129 strings)
2016-05-22 16:14:29 +02:00
Mladen Pejaković
cab770159d Translated using Weblate (Serbian)
Currently translated at 100.0% (129 of 129 strings)
2016-05-22 13:56:29 +02:00
Christian Schabesberger
7c2ff977d8 Merge branch 'download-manager' of git://github.com/satiricon/NewPipe into satiricon-download-manager 2016-05-22 12:47:24 +02:00
Christian Schabesberger
5bd9334f8f Merge branch 'master' of github.com:theScrabi/NewPipe 2016-05-22 12:44:41 +02:00
Christian Schabesberger
c5544df64c made StreamExtractor use StreamPreviewInfoCollector 2016-05-22 12:39:57 +02:00
Christian Schabesberger
c85e3c07d6 Merge pull request #287 from prashantkhurana/fix/Media-controls-on-main-screen
Added media volume control on main screen Fixes #38
2016-05-22 09:18:23 +02:00
Christian Schabesberger
674e1c0519 Merge pull request #294 from prashantkhurana/Feature/Hide-uploader-bug
Fix to hide uploader correctly
2016-05-22 09:16:37 +02:00
Prashant Khurana
7154a1edb8 Fix to hide uploader correctly 2016-05-15 22:20:28 -04:00
Licaon Kter
be1252e0e6 Translated using Weblate (Romanian)
Currently translated at 64.8% (70 of 108 strings)
2016-05-12 15:45:25 +02:00
Christian Schabesberger
a4ce6c707c update support lib 2016-05-10 00:26:32 +02:00
David
affce74b84 Added menu to download activity 2016-05-02 10:47:18 -03:00
David
730de4061f deleted some unused code and assets 2016-05-02 10:47:18 -03:00
David
3beafa2a74 Added new download dialog 2016-05-02 10:47:18 -03:00
David
c622923edd Fixed the download dialog. Next take it to the previous activity 2016-05-02 10:47:18 -03:00
David
6940021293 Fixed dir settings 2016-05-02 10:47:18 -03:00
David
0156a4f39e Added back button to download activity ActionBar 2016-05-02 10:47:18 -03:00
David
4bae12aa55 Embedded GigaGet download manager. First try. 2016-05-02 10:47:18 -03:00
M2ck
f08b1224c9 Translated using Weblate (French)
Currently translated at 100.0% (108 of 108 strings)
2016-05-02 15:44:32 +02:00
Prashant Khurana
477355db8f Added media volume control on main screen Fixes #38 2016-05-01 21:49:14 -04:00
Allan Nordhøy
11c89165c5 Translated using Weblate (Norwegian Bokmål)
Currently translated at 92.5% (100 of 108 strings)
2016-05-01 00:44:56 +02:00
riotism
825f28ab9a Translated using Weblate (Chinese (Hong Kong))
Currently translated at 92.5% (100 of 108 strings)
2016-04-28 00:44:12 +02:00
Marian Hanzel
54ff5e1dc6 Translated using Weblate (Slovak)
Currently translated at 100.0% (108 of 108 strings)
2016-04-27 18:45:19 +02:00
Gian Maria Viglianti
9b46418628 Translated using Weblate (Italian)
Currently translated at 100.0% (108 of 108 strings)
2016-04-25 13:12:42 +02:00
Benedikt Freisen
04597a9faf Translated using Weblate (German)
Currently translated at 100.0% (108 of 108 strings)
2016-04-18 21:24:55 +02:00
naofum
5b0994dc85 Translated using Weblate (Japanese)
Currently translated at 100.0% (108 of 108 strings)
2016-04-18 15:02:56 +02:00
Christian Schabesberger
7c852c69a3 add queeing videos as an future feature 2016-04-17 15:49:35 +02:00
devnoname120
df47e94ceb Translated using Weblate (French)
Currently translated at 100.0% (108 of 108 strings)
2016-04-17 03:44:30 +02:00
Sérgio Marques
3b68004005 Translated using Weblate (Portuguese)
Currently translated at 100.0% (108 of 108 strings)
2016-04-16 18:39:29 +02:00
devnoname120
5a9c327938 Translated using Weblate (French)
Currently translated at 99.0% (108 of 108 strings)
2016-04-15 01:10:28 +02:00
M2ck
3e31e9783c Translated using Weblate (French)
Currently translated at 99.0% (107 of 108 strings)
2016-04-15 01:10:25 +02:00
Yoo
46fb3639ec Translated using Weblate (Hungarian)
Currently translated at 99.0% (107 of 108 strings)
2016-04-14 18:44:40 +02:00
Rom1
a6eba57099 Translated using Weblate (French)
Currently translated at 99.0% (107 of 108 strings)
2016-04-13 14:49:46 +02:00
M2ck
c8481f961a Translated using Weblate (French)
Currently translated at 98.1% (106 of 108 strings)
2016-04-13 14:49:07 +02:00
Robin van der Vliet
56329f43fb Translated using Weblate (Esperanto)
Currently translated at 71.2% (77 of 108 strings)
2016-04-11 18:44:19 +02:00
Matej U
793fbfb5be Translated using Weblate (Slovenian)
Currently translated at 100.0% (108 of 108 strings)
2016-04-09 20:51:20 +02:00
Rom1
1d8334b762 Translated using Weblate (French)
Currently translated at 93.5% (101 of 108 strings)
2016-04-09 18:44:35 +02:00
Rom1
19330ac415 Translated using Weblate (English)
Currently translated at 100.0% (108 of 108 strings)
2016-04-09 18:44:21 +02:00
Ibrahim Derraz
7a015a0bda Translated using Weblate (French)
Currently translated at 91.6% (99 of 108 strings)
2016-04-07 16:49:27 +02:00
Rom1
f29c422c61 Translated using Weblate (French)
Currently translated at 90.7% (98 of 108 strings)
2016-04-07 16:49:10 +02:00
Ibrahim Derraz
99a369f604 Translated using Weblate (French)
Currently translated at 90.7% (98 of 108 strings)
2016-04-07 16:47:48 +02:00
Rom1
c1f0fb36ac Translated using Weblate (French)
Currently translated at 89.8% (97 of 108 strings)
2016-04-07 16:47:32 +02:00
Ibrahim Derraz
fa0a8905f7 Translated using Weblate (French)
Currently translated at 89.8% (97 of 108 strings)
2016-04-07 16:47:21 +02:00
Rom1
4e63a3269e Translated using Weblate (French)
Currently translated at 88.8% (96 of 108 strings)
2016-04-07 16:46:47 +02:00
Ibrahim Derraz
0f1873e295 Translated using Weblate (French)
Currently translated at 87.9% (95 of 108 strings)
2016-04-07 16:40:26 +02:00
Rom1
23fd28afd5 Translated using Weblate (French)
Currently translated at 86.1% (93 of 108 strings)
2016-04-07 16:38:33 +02:00
naofum
ad5a813a9a Translated using Weblate (Japanese)
Currently translated at 100.0% (108 of 108 strings)
2016-04-07 15:38:19 +02:00
Ibrahim Derraz
f245eedbdf Translated using Weblate (French)
Currently translated at 82.4% (89 of 108 strings)
2016-04-07 15:18:55 +02:00
Rom1
1ce6a6e8c5 Translated using Weblate (French)
Currently translated at 80.5% (87 of 108 strings)
2016-04-07 15:18:38 +02:00
Ibrahim Derraz
0ea7b5526c Translated using Weblate (French)
Currently translated at 80.5% (87 of 108 strings)
2016-04-07 15:18:07 +02:00
Rom1
b41e88f8f3 Translated using Weblate (French)
Currently translated at 79.6% (86 of 108 strings)
2016-04-07 15:17:56 +02:00
Ibrahim Derraz
82b9e79d99 Translated using Weblate (French)
Currently translated at 79.6% (86 of 108 strings)
2016-04-07 15:17:35 +02:00
Rom1
a5383fadb1 Translated using Weblate (French)
Currently translated at 74.0% (80 of 108 strings)
2016-04-07 15:15:24 +02:00
Ibrahim Derraz
bd7fb9bbe4 Translated using Weblate (French)
Currently translated at 73.1% (79 of 108 strings)
2016-04-07 15:15:14 +02:00
Rom1
1ddd0a333c Translated using Weblate (French)
Currently translated at 72.2% (78 of 108 strings)
2016-04-07 15:14:40 +02:00
Ibrahim Derraz
084fec08a6 Translated using Weblate (French)
Currently translated at 72.2% (78 of 108 strings)
2016-04-07 15:14:23 +02:00
Rom1
2b51448b49 Translated using Weblate (French)
Currently translated at 71.2% (77 of 108 strings)
2016-04-07 15:13:14 +02:00
Ibrahim Derraz
f4eee83477 Translated using Weblate (French)
Currently translated at 71.2% (77 of 108 strings)
2016-04-07 15:12:02 +02:00
Rom1
cd622c9e06 Translated using Weblate (French)
Currently translated at 70.3% (76 of 108 strings)
2016-04-07 15:11:52 +02:00
Ibrahim Derraz
7077ebfde2 Translated using Weblate (French)
Currently translated at 70.3% (76 of 108 strings)
2016-04-07 15:11:41 +02:00
Rom1
4862fecb12 Translated using Weblate (French)
Currently translated at 69.4% (75 of 108 strings)
2016-04-07 15:10:58 +02:00
YFdyh000
c189933705 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (108 of 108 strings)
2016-04-06 23:14:48 +02:00
Weblate
9c3f7a9139 Merge remote-tracking branch 'origin/master' 2016-04-06 23:12:51 +02:00
Zhaofeng Li
382bf5e936 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (108 of 108 strings)
2016-04-06 23:12:51 +02:00
Christian Schabesberger
e2fac962f3 Merge pull request #261 from zhaofengli/ui-strings-ocd-cure
Let's tweak the UI strings a bit
2016-04-06 23:12:47 +02:00
Gian Maria Viglianti
3071ebc0d5 Translated using Weblate (Italian)
Currently translated at 100.0% (108 of 108 strings)
2016-04-06 19:16:15 +02:00
Zhaofeng Li
a5fc6db1fa default_resolution_title: Fix capitalization
"Default Resolution" -> "Default resolution"

See https://www.google.com/design/spec/style/writing.html#writing-capitalization-punctuation
2016-04-06 20:08:29 +08:00
Zhaofeng Li
8060c6a775 strings.xml: Fix grammar
"Download path video" -> "Video download path"
"Download path audio" -> "Audio download path"
2016-04-06 20:06:00 +08:00
Zhaofeng Li
2a6e7f300c search_language_title: Change "Preferable" to "Preferred"
Why? See http://english.stackexchange.com/questions/128996/how-would-one-know-when-to-choose-preferred-or-preferable
2016-04-06 20:02:40 +08:00
Zhaofeng Li
98afe79eaa strings.xml: Remove unnecessary punctuations
Periods, colons and other unnecessary punctuations should not be used in labels.
See https://www.google.com/design/spec/style/writing.html#writing-capitalization-punctuation
2016-04-06 20:02:22 +08:00
halcyonest
a35590f9ea Translated using Weblate (English)
Currently translated at 100.0% (108 of 108 strings)
2016-03-29 03:44:20 +02:00
Marian Hanzel
f14f8c35b8 Translated using Weblate (Slovak)
Currently translated at 100.0% (108 of 108 strings)
2016-03-28 18:06:19 +02:00
Matej U
aa5c510c99 Translated using Weblate (Slovenian)
Currently translated at 100.0% (108 of 108 strings)
2016-03-27 18:57:00 +02:00
Benedikt Freisen
59f33a8def Translated using Weblate (German)
Currently translated at 100.0% (108 of 108 strings)
2016-03-27 16:19:49 +02:00
naofum
dbb4df598c Translated using Weblate (Japanese)
Currently translated at 100.0% (108 of 108 strings)
2016-03-27 03:45:53 +02:00
halcyonest
8452f52da0 Translated using Weblate (Korean)
Currently translated at 100.0% (108 of 108 strings)
2016-03-27 03:40:44 +02:00
Christian Schabesberger
db6613f562 yet another try to fix that test -.- 2016-03-25 20:19:43 +01:00
Christian Schabesberger
44d2775437 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-25 20:03:05 +01:00
Christian Schabesberger
a3326dc598 another try to fixe shitty viewcount test 2016-03-25 20:02:50 +01:00
Christian Schabesberger
0cd56ddeb8 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-25 19:37:59 +01:00
Christian Schabesberger
2a7f729e73 fixed unit test 2016-03-25 19:37:48 +01:00
Weblate
18301d8f8b Merge remote-tracking branch 'origin/master' 2016-03-25 19:34:47 +01:00
YFdyh000
8286437055 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (108 of 108 strings)
2016-03-25 19:34:46 +01:00
Christian Schabesberger
1bef7fbbf3 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-25 19:08:12 +01:00
YFdyh000
21e8318643 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (108 of 108 strings)
2016-03-25 19:06:56 +01:00
Christian Schabesberger
381f054daf Merge branch 'Start-screen-hint' of git://github.com/Ashanmaril/NewPipe into Ashanmaril-Start-screen-hint 2016-03-25 19:05:56 +01:00
Christian Schabesberger
c05d9303a9 fixed download location 2016-03-25 19:01:22 +01:00
Weblate
cca72a9e4e Merge remote-tracking branch 'origin/master' 2016-03-25 18:58:08 +01:00
Oleksandr Los
d4463e5f30 Translated using Weblate (Ukrainian)
Currently translated at 71.0% (76 of 107 strings)
2016-03-25 18:58:08 +01:00
Ibrahim Derraz
92155e2154 Translated using Weblate (French)
Currently translated at 65.4% (70 of 107 strings)
2016-03-25 18:58:07 +01:00
Christian Schabesberger
287fd0bf1e Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-25 13:57:19 +01:00
Christian Schabesberger
9e910d5501 fixed commons-lang problem & moved on to 0.7.8 2016-03-25 13:56:24 +01:00
YFdyh000
ff54b4d0c9 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (107 of 107 strings)
2016-03-25 06:45:09 +01:00
Oleksandr Los
af0b841bc3 Translated using Weblate (Ukrainian)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-03-24 22:57:17 +01:00
Matej U
665ea85613 Translated using Weblate (Slovenian)
Currently translated at 100.0% (107 of 107 strings)
2016-03-24 21:45:10 +01:00
Benedikt Freisen
de635392c6 Translated using Weblate (German)
Currently translated at 100.0% (107 of 107 strings)
2016-03-23 12:44:33 +01:00
YFdyh000
7814cca3d5 Translated using Weblate (Simplified Chinese)
Currently translated at 100.0% (107 of 107 strings)
2016-03-23 06:12:36 +01:00
Hayden
6c7204eae0 Show/hide message 2016-03-22 20:05:43 -06:00
Hayden
834d647011 Merge remote-tracking branch 'github/Start-screen-hint' into Start-screen-hint
# Conflicts:
#	app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java
2016-03-22 19:59:26 -06:00
Hayden
d872263b55 Got rid of imageview from testing 2016-03-22 19:55:00 -06:00
Hayden
4f8e4ca0ad Got rid of useless Toast from testing 2016-03-22 19:53:55 -06:00
Hayden
2abc9d0210 Text hint to start a search 2016-03-22 19:39:31 -06:00
Matej U
36fb942ce6 Translated using Weblate (Slovenian)
Currently translated at 100.0% (107 of 107 strings)
2016-03-22 19:10:20 +01:00
Tomáš Martykán
56476b35e3 Translated using Weblate (Czech)
Currently translated at 66.3% (71 of 107 strings)
2016-03-21 18:44:27 +01:00
hydroid7
38b3835891 Translated using Weblate (Hungarian)
Currently translated at 58.8% (63 of 107 strings)
2016-03-20 12:44:38 +01:00
naofum
ccf5be116a Translated using Weblate (Japanese)
Currently translated at 100.0% (107 of 107 strings)
2016-03-14 13:04:00 +01:00
Weblate
794ae4c5da Merge remote-tracking branch 'origin/master' 2016-03-13 22:38:50 +01:00
Mladen Pejaković
060e744924 Translated using Weblate (Serbian)
Currently translated at 98.1% (105 of 107 strings)
2016-03-13 22:38:50 +01:00
Christian Schabesberger
de62ed772f Merge branch 'master' of https://github.com/kamadi/NewPipe into kamadi-master 2016-03-13 22:36:33 +01:00
Christian Schabesberger
6a8c4a65c5 Merge pull request #237 from DevFactory/release/general-code-quality-fix-2
General code quality fix-2
2016-03-13 22:30:24 +01:00
Christian Schabesberger
03738aeb27 merged my changes with them of rrooij 2016-03-13 22:22:18 +01:00
Weblate
243cb8569e Merge remote-tracking branch 'origin/master' 2016-03-13 02:59:46 +01:00
Mladen Pejaković
1bd660fbbe Translated using Weblate (Serbian)
Currently translated at 98.1% (104 of 106 strings)
2016-03-13 02:59:46 +01:00
Christian Schabesberger
fec80b39f0 Merge pull request #238 from rrooij/yt_streampreviewextractor
Move YoutubeStreamPreviewInfoExtractor to separate class
2016-03-13 02:59:43 +01:00
rrooij
21768432c8 Move YoutubeStreamPreviewInfoExtractor to separate class
The class should be separate because channel support in the future would require video preview extraction too, which doesn't differ much from the extraction done from the search results.
2016-03-12 18:15:20 +01:00
Benedikt Freisen
e9b900ff28 Translated using Weblate (German)
Currently translated at 100.0% (106 of 106 strings)
2016-03-12 11:59:04 +01:00
naofum
c57cb8fec1 Translated using Weblate (Japanese)
Currently translated at 100.0% (106 of 106 strings)
2016-03-12 06:28:19 +01:00
Matej U
247681e3ef Translated using Weblate (Slovenian)
Currently translated at 100.0% (106 of 106 strings)
2016-03-11 23:46:28 +01:00
Faisal Hameed
2f9142419a Fixing squid:S1155, squid:S2293, squid:S1488 2016-03-12 02:01:47 +05:00
Christian Schabesberger
b84eb3df7f made stream type part of abstractVideoinfo 2016-03-11 16:20:02 +01:00
Christian Schabesberger
4058ec2ee9 fixed another livestream related issue 2016-03-11 15:43:50 +01:00
Christian Schabesberger
23a9061871 changed autoplay text 2016-03-11 15:10:13 +01:00
Weblate
9e95ca10b2 Merge remote-tracking branch 'origin/master' 2016-03-11 15:07:20 +01:00
Christian Schabesberger
4c0809d3d3 Translated using Weblate (German)
Currently translated at 100.0% (104 of 104 strings)
2016-03-11 15:07:20 +01:00
Christian Schabesberger
d43365f6e6 add custom error report function 2016-03-11 14:56:41 +01:00
Christian Schabesberger
c6ccc2b20d Merge pull request #232 from DevFactory/release/null-pointer-should-not-be-dereferenced-fix-1
Code quality fix - Null pointers should not be dereferenced.
2016-03-11 14:15:41 +01:00
Christian Schabesberger
31dd68be1d Merge pull request #233 from DevFactory/release/useless-parentheses-should-be-removed-fix-1
Code quality fix - Useless parentheses around expressions should be removed to prevent any misunderstanding.
2016-03-11 14:14:29 +01:00
Christian Schabesberger
1c94620c06 Merge pull request #234 from DevFactory/release/variable-should-comply-with-naming-conventions-fix-1
Code quality fix - Local variable and method parameter names should comply with a naming convention.
2016-03-11 14:13:51 +01:00
Weblate
82d214faa6 Merge remote-tracking branch 'origin/master' 2016-03-11 14:12:50 +01:00
Sérgio Marques
04b2e3689c Translated using Weblate (Portuguese)
Currently translated at 100.0% (104 of 104 strings)
2016-03-11 14:12:50 +01:00
Benedikt Volkmer
f00b8a3941 Translated using Weblate (German)
Currently translated at 100.0% (104 of 104 strings)
2016-03-11 14:12:49 +01:00
Henk de Vries
390cc9cfc9 Translated using Weblate (Dutch)
Currently translated at 95.1% (99 of 104 strings)
2016-03-11 14:12:49 +01:00
Christian Schabesberger
8259872e2d Merge pull request #235 from DevFactory/release/utility-classes-should-not-have-public-constructors-fix-1
Code quality fix - Utility classes should not have public constructors.
2016-03-11 14:12:45 +01:00
Faisal Hameed
1a3aaf86ee Fixing squid:S2259- Null pointers should not be dereferenced. 2016-03-10 15:07:23 +05:00
Faisal Hameed
cade4f932d Fixing squid:S00117- Local variable and method parameter names should comply with a naming convention. 2016-03-10 15:01:38 +05:00
Faisal Hameed
eb060602cd Fixing squid:S1118 - Utility classes should not have public constructors. 2016-03-10 14:50:42 +05:00
Faisal Hameed
805f046696 Fixing squid:UselessParenthesesCheck - Useless parentheses around expressions should be removed to prevent any misunderstanding. 2016-03-10 14:41:12 +05:00
Matej U
35e11e43de Translated using Weblate (Slovenian)
Currently translated at 100.0% (104 of 104 strings)
2016-03-08 21:22:44 +01:00
Mohamad Hasan Al Banna
ba15c6dc60 Translated using Weblate (Indonesian)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-03-08 16:29:26 +01:00
Christian Schabesberger
569c227a99 try to give gradle more memory for CI build 2016-03-08 02:43:00 +01:00
Christian Schabesberger
8fd7599158 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-08 02:22:35 +01:00
Christian Schabesberger
19418e5dfb fixed another parsing but related to livestreams 2016-03-08 02:22:23 +01:00
Christian Schabesberger
f90a163ede add --info to buildscript 2016-03-08 01:25:07 +01:00
Christian Schabesberger
8fb1fd3602 fixed image loading bug 2016-03-08 01:24:45 +01:00
Christian Schabesberger
0dbf2a347f moved on to version 0.7.7 2016-03-08 01:10:33 +01:00
Christian Schabesberger
38742fd5e8 fixed values-iw build failure 2016-03-08 01:09:39 +01:00
Weblate
67ce7e0979 Merge remote-tracking branch 'origin/master' 2016-03-08 01:06:49 +01:00
Benedikt Freisen
21a7e52f9a Translated using Weblate (German)
Currently translated at 99.0% (103 of 104 strings)
2016-03-08 01:06:49 +01:00
Christian Schabesberger
fcb445a381 removed --stacktrace form CI buildscript 2016-03-08 01:02:01 +01:00
Christian Schabesberger
f6450d4b4d removed not or almost not existing translations 2016-03-07 19:15:01 +01:00
Christian Schabesberger
a01d1b89b6 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-07 18:51:51 +01:00
Christian Schabesberger
0c9b6582cc made CI script print stack trace 2016-03-07 18:51:43 +01:00
Christian Schabesberger
2d47daabf8 add xxxhdpi app icon 2016-03-07 15:03:26 +01:00
Weblate
ce20cbe435 Merge remote-tracking branch 'origin/master' 2016-03-07 15:00:43 +01:00
Matej U
99e5415bfc Translated using Weblate (Slovenian)
Currently translated at 87.5% (91 of 104 strings)
2016-03-07 15:00:42 +01:00
madiyar
b2d935dd6d Restoring search query after orientation change in two pane mode 2016-03-07 13:05:05 +06:00
madiyar
eb66cc5db8 Restoring search query after orientation change 2016-03-07 12:58:48 +06:00
naofum
6d6b8363a8 Translated using Weblate (Japanese)
Currently translated at 100.0% (104 of 104 strings)
2016-03-06 12:19:11 +01:00
Mladen Pejaković
bf79b02e15 Translated using Weblate (Serbian)
Currently translated at 100.0% (104 of 104 strings)
2016-03-05 18:57:47 +01:00
Christian Schabesberger
3ce7eda3eb made newpipe handle not available like/dislike count 2016-03-05 18:35:28 +01:00
Christian Schabesberger
378e6b6547 fixed fix portrait view 2016-03-05 17:49:11 +01:00
Christian Schabesberger
f63b35e2c0 fixed search error 2016-03-05 17:35:57 +01:00
Christian Schabesberger
9a480cbe3e fixed backarrow on player_activity 2016-03-05 17:16:28 +01:00
Christian Schabesberger
76ca937bb8 set tor into experimental state 2016-03-05 17:04:37 +01:00
Christian Schabesberger
8a29567572 merge addExoplayer 2016-03-05 16:54:24 +01:00
Christian Schabesberger
839cd7d1c7 some small fixes 2016-03-05 16:24:47 +01:00
Christian Schabesberger
0bfc7a9177 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-03-05 16:15:00 +01:00
Christian Schabesberger
26e11f96e0 add streamtype field 2016-03-04 15:18:04 +01:00
Christian Schabesberger
86c36acedc removed android code from extractor side 2016-03-04 14:25:37 +01:00
Christian Schabesberger
2318ad2bde changed viewcount notation 2016-03-04 14:16:02 +01:00
Christian Schabesberger
9548dfabd6 made service list do propper error handling 2016-03-04 14:10:41 +01:00
Christian Schabesberger
0c716c12d7 fixed viewcount test again 2016-03-04 13:51:50 +01:00
Weblate
08dd176753 Merge remote-tracking branch 'origin/master' 2016-03-04 13:49:06 +01:00
Thejesh GN
07086bfb3e Translated using Weblate (Kannada)
Currently translated at 30.5% (26 of 85 strings)
2016-03-04 13:49:06 +01:00
Christian Schabesberger
b1d2e64450 ad service_id field, and pulled video/audio stream out of streaminfo 2016-03-04 13:45:41 +01:00
Christian Schabesberger
d9cd928100 fixed audio settings changed bug 2016-03-02 23:23:52 +01:00
naofum
37ec26c8fd Translated using Weblate (Japanese)
Currently translated at 100.0% (85 of 85 strings)
2016-03-02 13:05:54 +01:00
Christian Schabesberger
68b7d9cdff made duration an integer, and made youtubesearch engine throw more parsingexceptions 2016-03-02 02:36:45 +01:00
Christian Schabesberger
3aecd15916 Merge branch 'advancedErrorHandling' 2016-03-02 00:29:56 +01:00
Christian Schabesberger
97d76aee18 fixed failing unit test 2016-03-01 23:54:26 +01:00
Christian Schabesberger
781bf8e7ec fixed yet another bug 2016-03-01 23:28:22 +01:00
Christian Schabesberger
77b9457707 add error handling to suggestions 2016-03-01 18:43:36 +01:00
Christian Schabesberger
1210ab0de0 changed color of snackbar action text 2016-02-29 21:22:16 +01:00
Christian Schabesberger
3c93c4714e fixed crash during crash report 2016-02-29 21:13:02 +01:00
Christian Schabesberger
f90a1ede70 fixed some more bugs 2016-02-29 21:06:00 +01:00
Christian Schabesberger
028354b283 fixed some bugs 2016-02-29 20:33:28 +01:00
Christian Schabesberger
18493a578d made error message be displayed inside erroractivity 2016-02-29 19:23:01 +01:00
Christian Schabesberger
1829dc79c8 make erroractivity handle search engine exceptions 2016-02-29 19:02:40 +01:00
Weblate
7575e8fbe3 Merge remote-tracking branch 'origin/master' 2016-02-29 16:16:54 +01:00
Christian Schabesberger
eed9915c12 add missing gpl3 header to SuggestionListAdapter 2016-02-29 16:19:34 +01:00
Filip Sebastian
be71e45954 Translated using Weblate (Romanian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-29 16:16:54 +01:00
Kamil Modzelewski
3a7978eca0 Translated using Weblate (Polish)
Currently translated at 54.1% (39 of 72 strings)
2016-02-29 16:16:53 +01:00
naofum
c37d2250d4 Translated using Weblate (Japanese)
Currently translated at 100.0% (72 of 72 strings)
2016-02-29 16:16:53 +01:00
Benedikt Freisen
45819d1cd4 Translated using Weblate (German)
Currently translated at 98.6% (71 of 72 strings)
2016-02-29 16:16:53 +01:00
Christian Schabesberger
4ac36af40c made extractor not throw exception upon missing dash mpd 2016-02-29 16:15:15 +01:00
Christian Schabesberger
1a2840b33f made ui handle missing information on search 2016-02-29 16:10:46 +01:00
Christian Schabesberger
d7e75e6011 restructured search engine 2016-02-29 15:59:06 +01:00
Gian Maria Viglianti
73316b87a3 Translated using Weblate (English)
Currently translated at 100.0% (72 of 72 strings)
2016-02-29 03:44:20 +01:00
Matej U
46402691b0 Translated using Weblate (Slovenian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-27 23:05:13 +01:00
Filip Sebastian
e7cef4549f Translated using Weblate (Romanian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-27 17:51:43 +01:00
Christian Schabesberger
737a41f45b display error message 2016-02-27 17:02:38 +01:00
Christian Schabesberger
045ca40a77 renamed video classes to stream classes 2016-02-27 16:37:15 +01:00
Christian Schabesberger
b1fe197c11 changed crashreport email address 2016-02-27 15:57:37 +01:00
Mladen Pejaković
8888530ae3 Translated using Weblate (Serbian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-27 15:34:44 +01:00
Christian Schabesberger
2d51c7428e add ip and timestamp 2016-02-27 15:02:28 +01:00
Christian Schabesberger
863e2a80a2 set errors mail address 2016-02-27 02:26:06 +01:00
Weblate
41d17d2a47 Merge remote-tracking branch 'origin/master' 2016-02-27 02:12:18 +01:00
Christian Schabesberger
36934468d6 uppdate support framework 2016-02-27 02:14:55 +01:00
Thejesh GN
5029ce8728 Translated using Weblate (Kannada)
Currently translated at 1.3% (1 of 72 strings)
2016-02-27 02:12:17 +01:00
Gian Maria Viglianti
e6ab24bcb4 Translated using Weblate (Italian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-27 02:12:17 +01:00
Christian Schabesberger
f3bd263ada new website for newpipe 2016-02-27 02:11:31 +01:00
Gian Maria Viglianti
db7ab3ffce Translated using Weblate (Italian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-27 01:37:42 +01:00
Thejesh GN
85c3755b96 Translated using Weblate (Kannada)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-26 10:28:11 +01:00
Christian Schabesberger
5decd55551 fixed another pattern problem 2016-02-26 01:42:38 +01:00
Christian Schabesberger
bc468b6f36 fixed stream exception handling 2016-02-26 01:32:44 +01:00
Christian Schabesberger
369d9204d9 add send via mail/share feature 2016-02-25 23:19:43 +01:00
Christian Schabesberger
7caf7be97e add info box 2016-02-25 22:02:42 +01:00
Christian Schabesberger
64c423902a made error handling work a bit 2016-02-25 03:43:13 +01:00
Christian Schabesberger
27a2dee3bd created error report activity 2016-02-24 23:12:02 +01:00
Christian Schabesberger
11d3aeb0dd fixed faling searchengine unittest 2016-02-24 22:36:16 +01:00
Christian Schabesberger
f54d8d318a remove parcelabel from VideoInfoItem 2016-02-24 22:25:51 +01:00
Christian Schabesberger
210f2ef452 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-24 22:12:21 +01:00
Christian Schabesberger
d0bab6183a fixed related view 0 view count error 2016-02-24 22:12:13 +01:00
Christian Schabesberger
3441aceba3 fixed viewcount failure 2016-02-24 16:44:46 +01:00
Weblate
0908b9cd76 Merge remote-tracking branch 'origin/master' 2016-02-24 16:42:14 +01:00
vadin
67494ad4c4 Translated using Weblate (Spanish)
Currently translated at 98.6% (71 of 72 strings)
2016-02-24 16:42:14 +01:00
naofum
5d8f75beb4 Translated using Weblate (Japanese)
Currently translated at 100.0% (72 of 72 strings)
2016-02-24 15:06:59 +01:00
Christian Schabesberger
8e7fde99db fix bitcoin qrcode 2016-02-24 13:34:41 +01:00
Christian Schabesberger
bfdf165584 add bitcoin donations 2016-02-24 13:29:53 +01:00
Weblate
9427ebd489 Merge remote-tracking branch 'origin/master' 2016-02-23 23:33:55 +01:00
Christian Schabesberger
e4f753ae82 fixed emty search query on suggestions error 2016-02-23 23:36:02 +01:00
Benedikt Freisen
f2d9d3c2d7 Translated using Weblate (German)
Currently translated at 98.6% (71 of 72 strings)
2016-02-23 23:33:55 +01:00
Nathan Follens
04c5f31cc1 Translated using Weblate (Dutch)
Currently translated at 100.0% (72 of 72 strings)
2016-02-23 23:33:55 +01:00
Matej U
4ea86b714e Translated using Weblate (Slovenian)
Currently translated at 100.0% (72 of 72 strings)
2016-02-23 18:33:20 +01:00
Nathan Follens
cc0b96cba4 Translated using Weblate (Dutch)
Currently translated at 100.0% (72 of 72 strings)
2016-02-23 18:00:54 +01:00
Christian Schabesberger
9e176f8400 Merge branch 'kamadi-master' 2016-02-23 16:52:52 +01:00
Christian Schabesberger
7195ff349b fixed toast issue of the previous commit 2016-02-23 16:42:04 +01:00
Christian Schabesberger
8048ad343e add toast for suggestion error handling 2016-02-23 16:34:14 +01:00
Christian Schabesberger
799a27ec84 Merge branch 'master' of https://github.com/kamadi/NewPipe into kamadi-master 2016-02-23 16:21:16 +01:00
Christian Schabesberger
c7c77ab20c fixed another pattern problem 2016-02-23 15:25:34 +01:00
madiyar
8fc113cc52 Added country language param to the suggestionList method in search engine 2016-02-23 16:22:49 +06:00
madiyar
c7679bec87 Added suggestion to the searching 2016-02-23 15:01:59 +06:00
madiyar
3301d8b4fb Created suggestion adapter 2016-02-23 14:36:24 +06:00
Christian Schabesberger
f5892093a9 made exoplayer work with youtube again 2016-02-23 01:56:04 +01:00
Christian Schabesberger
b06238ba5d initial changes 2016-02-22 20:28:37 +01:00
Christian Schabesberger
dddcc80f30 merged faridk's code 2016-02-22 19:58:04 +01:00
Christian Schabesberger
8854c8c9d0 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-22 19:19:22 +01:00
Christian Schabesberger
d02f441eb0 add age restricted material to description 2016-02-22 19:19:13 +01:00
Christian Schabesberger
ff89dd00b6 Merge branch 'rrooij-age_restriction' 2016-02-22 19:18:22 +01:00
Christian Schabesberger
7041e63268 merged age restricted video request 2016-02-22 19:17:05 +01:00
Weblate
8126fdcd15 Merge remote-tracking branch 'origin/master' 2016-02-22 19:16:57 +01:00
Selim
2d61a2f251 Translated using Weblate (Turkish)
Currently translated at 31.8% (22 of 69 strings)
2016-02-22 19:16:57 +01:00
Matej U
7594ee9dbe Translated using Weblate (Slovenian)
Currently translated at 100.0% (69 of 69 strings)
2016-02-22 19:16:56 +01:00
naofum
0862a38599 Translated using Weblate (Japanese)
Currently translated at 100.0% (69 of 69 strings)
2016-02-22 16:37:05 +01:00
Selim
bf7dc462e8 Translated using Weblate (Turkish)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-22 13:46:14 +01:00
Christian Schabesberger
65b6aaec8e moved on to 0.7.6 2016-02-21 22:57:07 +01:00
Christian Schabesberger
e08aa14eab better detection for livestreams 2016-02-21 22:25:45 +01:00
Christian Schabesberger
851028997a fixed json error from the last commit 2016-02-21 21:15:39 +01:00
Christian Schabesberger
a1479d04df fixed some searchengine errors 2016-02-21 21:08:14 +01:00
rrooij
d12af16f46 VideoItemDetailFragment: check for next vid
Check if the next video is available before loading the thumbnails.
2016-02-21 19:07:24 +01:00
rrooij
2edfcb78fe YTStreamExtractor: implement getAgeRestriction 2016-02-21 18:45:28 +01:00
rrooij
3f0947fa5b Add unit test for restricted YouTube videos 2016-02-21 18:25:18 +01:00
rrooij
d2b808e540 YTStreamExtractor: fix audio tracks on restricted
Fix audio tracks on restriced videos.
2016-02-21 18:24:53 +01:00
Christian Schabesberger
2995a7dc8f actual fix for androi 6.0 notification problem
Notification buttons weren't respondig to clicks. Now they do.
2016-02-21 18:12:00 +01:00
Christian Schabesberger
819db0a30b antifix for android 6.0 notification z order problem 2016-02-21 17:55:00 +01:00
rrooij
4d727245e1 YTStreamExtractor: add support for age restricted
YouTube age restricted videos are now kind of supported. This is not a
final solution to this problem and this commit still crashes because of
some problem with the thumbnail.
2016-02-21 16:39:08 +01:00
Weblate
d8281aeb34 Merge remote-tracking branch 'origin/master' 2016-02-21 01:40:55 +01:00
LelixSuper
cd0f2061b5 Translated using Weblate (Italian)
Currently translated at 100.0% (68 of 68 strings)
2016-02-21 01:40:55 +01:00
Christian Schabesberger
96928d46ca Merge pull request #199 from szafir1100/develop
used regex to delete spaces inside parseLong() argument
2016-02-21 01:40:50 +01:00
LelixSuper
6d55ac2199 Translated using Weblate (Italian)
Currently translated at 100.0% (68 of 68 strings)
2016-02-20 15:16:59 +01:00
Tomasz Marzeion
80dae6ece7 used regex to delete spaces inside parseLong() argument 2016-02-20 13:49:47 +01:00
Matej U
a1a12ca9f7 Translated using Weblate (Slovenian)
Currently translated at 100.0% (68 of 68 strings)
2016-02-19 15:46:49 +01:00
Christian Schabesberger
5a594173fa Merge pull request #193 from satiricon/fix-autoplay
Fix ArrayIndexOutOfBoundsException when using autoplay
2016-02-19 15:14:06 +01:00
Christian Schabesberger
1e989945b9 moved on to 0.7.5 2016-02-19 14:40:49 +01:00
Christian Schabesberger
679bef849c Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-19 14:40:20 +01:00
Christian Schabesberger
1c17be9760 made new notification layout available for older platforms 2016-02-19 13:22:49 +01:00
naofum
6def0e3115 Translated using Weblate (Japanese)
Currently translated at 100.0% (68 of 68 strings)
2016-02-19 12:51:38 +01:00
David
fd3436d5c0 Fix ArrayIndexOutOfBoundsException when using autoplay 2016-02-18 13:40:26 -03:00
Christian Schabesberger
a94f9fd3e5 made the ui react on missing information 2016-02-18 13:49:01 +01:00
Christian Schabesberger
77850464d4 renamed crawler into extractor 2016-02-18 11:50:22 +01:00
Christian Schabesberger
3e9edba189 fix broken unit test 2016-02-18 11:47:21 +01:00
Christian Schabesberger
3d168542fe add arabic translation 2016-02-18 00:00:47 +01:00
Christian Schabesberger
0de00e26d8 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-17 23:55:32 +01:00
Christian Schabesberger
f0705c612e removed play fab button 2016-02-17 23:55:19 +01:00
Christian Schabesberger
648b9b5d02 made the ui more accommodating for not available audio streams 2016-02-17 21:39:41 +01:00
Christian Schabesberger
b15a0b92f9 add support for attribution_link links 2016-02-17 20:29:31 +01:00
Christian Schabesberger
80482c0578 made settings_keys unsupportable 2016-02-17 19:23:23 +01:00
Weblate
16701923a1 Merge remote-tracking branch 'origin/master' 2016-02-17 19:21:20 +01:00
kamadi
67cee06523 Translated using Weblate (Russian)
Currently translated at 80.5% (54 of 67 strings)
2016-02-17 19:21:20 +01:00
Omar Kharrab
685dab39af Translated using Weblate (French)
Currently translated at 97.0% (65 of 67 strings)
2016-02-17 19:21:19 +01:00
David Duong
0ff9555cc4 Translated using Weblate (Czech)
Currently translated at 100.0% (67 of 67 strings)
2016-02-17 18:44:14 +01:00
Robin van der Vliet
4f808dd17d Translated using Weblate (Dutch)
Currently translated at 65.6% (44 of 67 strings)
2016-02-17 00:44:16 +01:00
vadin
69d71dac36 Translated using Weblate (Spanish)
Currently translated at 100.0% (67 of 67 strings)
2016-02-16 23:18:33 +01:00
Jossi Wolf
4880319991 Translated using Weblate (German)
Currently translated at 98.5% (66 of 67 strings)
2016-02-16 21:44:52 +01:00
Robin van der Vliet
13b9850b39 Translated using Weblate (Esperanto)
Currently translated at 100.0% (67 of 67 strings)

Imperative because it is a command to the user.
2016-02-16 17:29:05 +01:00
Robin van der Vliet
366f645eda Translated using Weblate (Esperanto)
Currently translated at 97.0% (65 of 67 strings)

Translated "media center" just as "application", if somebody has a better translation please change it.
2016-02-16 17:28:40 +01:00
Robin van der Vliet
dcf7190c90 Translated using Weblate (Esperanto)
Currently translated at 91.0% (61 of 67 strings)

elŝutujo = container for downloads
2016-02-16 17:22:13 +01:00
Robin van der Vliet
ae6647276c Translated using Weblate (Esperanto)
Currently translated at 86.5% (58 of 67 strings)

A bit long
2016-02-16 17:14:35 +01:00
Robin van der Vliet
460ff37f7a Translated using Weblate (Esperanto)
Currently translated at 79.1% (53 of 67 strings)

A bit long because
2016-02-16 17:05:14 +01:00
Robin van der Vliet
e7ef913416 Translated using Weblate (Esperanto)
Currently translated at 77.6% (52 of 67 strings)

Added "the app" because the accusative cannot really go on the word "Kore"
2016-02-16 17:03:53 +01:00
Robin van der Vliet
c149050a3a Translated using Weblate (Esperanto)
Currently translated at 71.6% (48 of 67 strings)

Added "the app" because the accusative cannot really go on the word "VLC"
2016-02-16 16:59:18 +01:00
Robin van der Vliet
a4e5ca54db Translated using Weblate (Esperanto)
Currently translated at 70.1% (47 of 67 strings)

Intent untranslated because there is not really a common translation. If somebody has a better translation, please change it.
2016-02-16 16:58:13 +01:00
Robin van der Vliet
cb81fd3353 Translated using Weblate (Esperanto)
Currently translated at 68.6% (46 of 67 strings)

Added "the program" because the accusative cannot really go on the word "Tor"
2016-02-16 16:57:28 +01:00
Farid
3a8611ebf8 Added ExoPlayer support 2016-02-15 18:49:58 -08:00
David Duong
352a883b5d Translated using Weblate (Czech)
Currently translated at 100.0% (67 of 67 strings)
2016-02-15 18:04:52 +01:00
David Duong
5247b22ef4 Translated using Weblate (Czech)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-15 17:33:44 +01:00
Robin van der Vliet
1bf00e80b0 Translated using Weblate (Esperanto)
Currently translated at 67.1% (45 of 67 strings)
2016-02-14 23:57:46 +01:00
Robin van der Vliet
6331d9b7a4 Translated using Weblate (Esperanto)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-14 23:44:51 +01:00
Marian Hanzel
0deb0ad851 Translated using Weblate (Slovak)
Currently translated at 100.0% (67 of 67 strings)
2016-02-14 21:45:11 +01:00
Matej U
3b42041c4e Translated using Weblate (Slovenian)
Currently translated at 100.0% (67 of 67 strings)
2016-02-14 21:23:03 +01:00
Benedikt Freisen
d8987aa94a Translated using Weblate (German)
Currently translated at 98.5% (66 of 67 strings)

Where readable and unambiguous, the compound-noun-spelling without hyphen is usually preferred.
2016-02-14 21:06:39 +01:00
Mladen Pejaković
19ed16efc6 Translated using Weblate (Serbian)
Currently translated at 100.0% (67 of 67 strings)
2016-02-14 11:33:57 +01:00
Benedikt Freisen
0e32d70aef Translated using Weblate (German)
Currently translated at 98.5% (66 of 67 strings)
2016-02-12 22:59:12 +01:00
Marian Hanzel
5b71f279fd Translated using Weblate (Slovak)
Currently translated at 100.0% (67 of 67 strings)
2016-02-12 19:59:06 +01:00
Marian Hanzel
6d170ffb16 Translated using Weblate (Slovak)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-12 19:29:38 +01:00
Christian Schabesberger
72d90374a0 moved on to 0.7.4 2016-02-12 15:32:16 +01:00
Christian Schabesberger
fc8160acda fixed autoplay bug 2016-02-12 15:29:11 +01:00
Christian Schabesberger
751ffb9de9 quick and dirty solution for download/audio bug
Youtube has changed (again) this time it was a bit harder,
therfor the changes are deeper. May be still a bit unstable.
2016-02-12 01:29:14 +01:00
Christian Schabesberger
60d636940d set orbot/tor support into experimental status 2016-02-10 12:09:43 +01:00
Christian Schabesberger
7a5cca519a Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-08 18:46:56 +01:00
Christian Schabesberger
1e93d06a25 restructured ActionbarHandler 2016-02-08 18:46:42 +01:00
naofum
4341f8aaec Translated using Weblate (Japanese)
Currently translated at 100.0% (67 of 67 strings)
2016-02-08 12:44:42 +01:00
Licaon Kter
46022d60f3 Translated using Weblate (Romanian)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-07 22:16:35 +01:00
Sérgio Marques
80ddc76926 Translated using Weblate (Portuguese)
Currently translated at 100.0% (67 of 67 strings)
2016-02-06 23:07:05 +01:00
naofum
bd999b4b0a Translated using Weblate (Japanese)
Currently translated at 100.0% (67 of 67 strings)
2016-02-06 11:42:08 +01:00
Christian Schabesberger
4cdc387338 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-05 17:14:18 +01:00
Christian Schabesberger
df258a0003 Merge branch 'algoprog-master' 2016-02-05 17:10:00 +01:00
Christian Schabesberger
7cc1c0fbdd merge code, and adjust code 2016-02-05 17:09:29 +01:00
Mladen Pejaković
42644c956b Translated using Weblate (Serbian)
Currently translated at 100.0% (67 of 67 strings)
2016-02-05 14:50:14 +01:00
Weblate
00eaedcbfa Merge remote-tracking branch 'origin/master' 2016-02-05 14:38:53 +01:00
Chris Samarinas
1ff5a97c85 Translated using Weblate (Greek)
Currently translated at 100.0% (61 of 61 strings)
2016-02-05 14:38:52 +01:00
Christian Schabesberger
241414f81b Merge pull request #167 from theScrabi/crawlerRefactor
Crawler refactor
2016-02-05 14:38:48 +01:00
Christian Schabesberger
1bf046a8ba made all arrays into lists 2016-02-05 14:09:04 +01:00
Christian Schabesberger
61471fdd3c renamed UrlIdHandler into VideoUrlIdHandler 2016-02-05 13:34:44 +01:00
Allan Nordhøy
a0524fb136 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (61 of 61 strings)
2016-02-05 01:55:35 +01:00
Allan Nordhøy
fa39389a64 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-05 01:38:27 +01:00
Chris Samarinas
697a24e699 Translated using Weblate (Greek)
Currently translated at 100.0% (61 of 61 strings)
2016-02-04 06:10:42 +01:00
Chris Samarinas
cf3bb87a54 Translated using Weblate (Greek)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-02-04 05:46:47 +01:00
Christian Schabesberger
14fb7d8a7a fixed failing tests 2016-02-02 19:01:53 +01:00
Christian Schabesberger
d097363b24 restructure parser 2016-02-02 18:43:20 +01:00
Christian Schabesberger
bad576c23d got rid of getVideoInfo() in youtube crawler 2016-02-02 14:06:09 +01:00
Weblate
8d9e4e7442 Merge remote-tracking branch 'origin/master' 2016-02-01 13:44:46 +01:00
Christian Schabesberger
431d03c63f Merge branch 'master' of github.com:theScrabi/NewPipe 2016-02-01 13:46:01 +01:00
Christian Schabesberger
24321731d9 Merge branch 'iit2014086-master' 2016-02-01 13:45:44 +01:00
Christian Schabesberger
fddcade1fb removed unnececeary call of setVolumeControlStream() 2016-02-01 13:45:22 +01:00
theshayy
a0aa7dcdc1 Translated using Weblate (French)
Currently translated at 100.0% (61 of 61 strings)
2016-02-01 13:44:46 +01:00
Teja Vojjala
d3e9f354b3 Update SettingsActivity.java 2016-02-01 15:00:08 +05:30
Teja Vojjala
e958334406 Update VideoItemListActivity.java 2016-02-01 14:29:49 +05:30
Teja Vojjala
a42029970d Update VideoItemDetailActivity.java 2016-02-01 14:29:28 +05:30
Teja Vojjala
2108e09e13 Update PlayVideoActivity.java 2016-02-01 14:28:38 +05:30
Teja Vojjala
8c010093e8 Update SettingsActivity.java 2016-02-01 14:27:24 +05:30
Teja Vojjala
adc98be441 Update PanicResponderActivity.java 2016-02-01 14:25:23 +05:30
Christian Schabesberger
fb942912db disable gema test agian 2016-01-31 20:16:21 +01:00
Christian Schabesberger
7f12b58722 use java error system in the crawler 2016-01-31 19:57:30 +01:00
Éfrit
05d58f8f98 Translated using Weblate (French)
Currently translated at 100.0% (61 of 61 strings)
2016-01-31 12:49:00 +01:00
Christian Schabesberger
46c2db310a add suport for dash 2016-01-30 00:22:16 +01:00
Teja Vojjala
607408b9b9 Update PanicResponderActivity.java 2016-01-29 20:21:44 +05:30
Teja Vojjala
b81e8cb81a Update SettingsActivity.java 2016-01-29 20:20:55 +05:30
Teja Vojjala
44ef04d90a Update PlayVideoActivity.java 2016-01-29 20:19:09 +05:30
Teja Vojjala
3e9d84b109 Merge pull request #2 from iit2014086/iit2014086-patch-2
Update VideoItemDetailActivity.java
2016-01-29 20:17:24 +05:30
Teja Vojjala
aa2d8d4833 Update VideoItemDetailActivity.java 2016-01-29 20:16:57 +05:30
Teja Vojjala
55f63b948b Merge pull request #1 from iit2014086/iit2014086-patch-1
Update VideoItemListActivity.java
2016-01-29 20:09:13 +05:30
Teja Vojjala
cece543d6b Update VideoItemListActivity.java 2016-01-29 20:07:15 +05:30
Christian Schabesberger
9204a89319 fiexed some licence headers 2016-01-28 23:27:16 +01:00
Christian Schabesberger
f8ed96bb25 renamed services into crawer 2016-01-28 21:34:35 +01:00
Christian Schabesberger
54d318bf04 detatch android related downloader from crawler 2016-01-28 21:21:19 +01:00
Christian Schabesberger
f152d66cd8 fixed some bugs 2016-01-28 12:10:50 +01:00
Sérgio Marques
576786c751 Translated using Weblate (Portuguese)
Currently translated at 100.0% (61 of 61 strings)
2016-01-19 00:22:40 +01:00
halcyonest
a6b7cd3202 Translated using Weblate (Korean)
Currently translated at 100.0% (61 of 61 strings)
2016-01-16 12:44:51 +01:00
Yoo
ea9caaaaf0 Translated using Weblate (Hungarian)
Currently translated at 96.7% (59 of 61 strings)
2016-01-14 21:44:37 +01:00
Matej U
22d8f434be Translated using Weblate (Slovenian)
Currently translated at 100.0% (61 of 61 strings)
2016-01-14 15:45:12 +01:00
halcyonest
8360c10141 Translated using Weblate (Korean)
Currently translated at 100.0% (61 of 61 strings)
2016-01-12 10:14:37 +01:00
Matej U
750dc6f2cc Translated using Weblate (Slovenian)
Currently translated at 100.0% (61 of 61 strings)
2016-01-10 14:22:05 +01:00
riotism
47b556544d Translated using Weblate (Chinese (Taiwan))
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 23:06:53 +01:00
riotism
f6cee739a6 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 23:02:34 +01:00
riotism
d1afe0028c Translated using Weblate (Chinese (China))
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 22:59:42 +01:00
M2ck
a4cace1ef7 Translated using Weblate (French)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 20:55:00 +01:00
red
707ac8be27 Translated using Weblate (French)
Currently translated at 81.9% (50 of 61 strings)
2016-01-09 20:37:38 +01:00
Weblate
2f2254966a Merge remote-tracking branch 'origin/master' 2016-01-09 15:04:05 +01:00
Christian Schabesberger
eb57675f55 Translated using Weblate (German)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 15:04:05 +01:00
Christian Schabesberger
dde93c5ccf Translated using Weblate (English)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 15:04:05 +01:00
Christian Schabesberger
886b5959f7 Merge pull request #149 from narutosanjiv/master
ProgressBar must stop incase of network failure
2016-01-09 15:04:02 +01:00
naofum
dc44546ac7 Translated using Weblate (Japanese)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 13:38:56 +01:00
Sanjiv Jha
42c6698732 ProgressBar must stop incase of network failure in videolist & detail page 2016-01-09 16:39:31 +05:30
Mladen Pejaković
bd014a107f Translated using Weblate (Serbian)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 02:36:00 +01:00
Christian Schabesberger
3a7298bb99 Translated using Weblate (German)
Currently translated at 100.0% (61 of 61 strings)
2016-01-09 00:09:55 +01:00
Christian Schabesberger
aa06e3490d Merge branch 'master' of github.com:theScrabi/NewPipe 2016-01-08 22:22:55 +01:00
Christian Schabesberger
ece889b36b moved on to 0.7.3 2016-01-08 22:22:39 +01:00
Christian Schabesberger
9848f19ce6 Merge github.com:k3b/NewPipe into k3bMaster 2016-01-08 22:04:42 +01:00
Weblate
e59b087057 Merge remote-tracking branch 'origin/master' 2016-01-08 22:00:27 +01:00
Greg
5b451d1ac7 Translated using Weblate (Spanish)
Currently translated at 64.2% (36 of 56 strings)
2016-01-08 22:00:27 +01:00
Greg
f050c05b3c Translated using Weblate (Russian)
Currently translated at 98.2% (55 of 56 strings)
2016-01-08 22:00:27 +01:00
Sérgio Marques
06b8edefbf Translated using Weblate (Portuguese)
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 22:00:26 +01:00
Greg
f3a2a28398 Translated using Weblate (German)
Currently translated at 91.0% (51 of 56 strings)
2016-01-08 22:00:26 +01:00
Greg
9b0a1fc2ec Translated using Weblate (English)
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 22:00:26 +01:00
riotism
c87ab234eb Translated using Weblate (Chinese (Taiwan))
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 22:00:25 +01:00
riotism
68468756a8 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 22:00:24 +01:00
riotism
9016df0195 Translated using Weblate (Chinese (China))
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 22:00:24 +01:00
Christian Schabesberger
7acece9705 Merge pull request #145 from 42SK/master
Fixed #143
2016-01-08 22:00:21 +01:00
red
d1896c23c0 Translated using Weblate (French)
Currently translated at 100.0% (56 of 56 strings)
2016-01-08 14:04:29 +01:00
riotism
dae19f03e0 Translated using Weblate (Chinese (China))
Currently translated at 100.0% (56 of 56 strings)
2016-01-07 23:07:42 +01:00
riotism
9dafccf0f7 Translated using Weblate (Chinese (China))
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-01-07 22:46:44 +01:00
riotism
5f270c41ae Translated using Weblate (Chinese (Taiwan))
Currently translated at 100.0% (56 of 56 strings)
2016-01-07 22:46:12 +01:00
riotism
f9f80e9003 Translated using Weblate (Chinese (Taiwan))
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-01-07 22:08:02 +01:00
riotism
c5063d4269 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100.0% (56 of 56 strings)
2016-01-07 22:06:57 +01:00
riotism
ccbe18ec1c Translated using Weblate (Chinese (Hong Kong))
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-01-07 21:21:58 +01:00
k3b
321a8a8b25 Translated using Weblate (German)
Currently translated at 91.0% (51 of 56 strings)
2016-01-07 20:20:57 +01:00
k3b
77a9560376 #143 #44 #42 #22: Fixed some download problems with invalid directories or filenames. Added user Feedback. Different settings for audio and video download dir. 2016-01-07 14:32:16 +01:00
k3b
058a039a82 #143 #44 #42 #22: Fixed some download problems with invalid directories or filenames. Added user Feedback. Different settings for audio and video download dir. 2016-01-07 14:22:55 +01:00
naofum
7c744703e4 Translated using Weblate (Japanese)
Currently translated at 100.0% (56 of 56 strings)
2016-01-07 14:15:56 +01:00
42SK
a934cbb085 Fixed #143 2016-01-07 13:28:17 +01:00
Sérgio Marques
cf4158c0d0 Translated using Weblate (Portuguese)
Currently translated at 100.0% (56 of 56 strings)
2016-01-07 00:48:13 +01:00
M2ck
dc56eab9b6 Translated using Weblate (French)
Currently translated at 100.0% (56 of 56 strings)
2016-01-06 16:47:54 +01:00
Weblate
37d1f59132 Merge remote-tracking branch 'origin/master' 2016-01-06 15:13:03 +01:00
Christian Schabesberger
ab0ce55411 merge unitTesting 2016-01-06 15:13:55 +01:00
Matej U
c1d66596d1 Translated using Weblate (Slovenian)
Currently translated at 100.0% (56 of 56 strings)
2016-01-06 15:13:03 +01:00
Mladen Pejaković
cbfccdf0d3 Translated using Weblate (Serbian)
Currently translated at 100.0% (56 of 56 strings)
2016-01-06 15:13:02 +01:00
Christian Schabesberger
9362037177 remove theme option since it's not yet working 2016-01-06 15:00:33 +01:00
Matej U
e25c93bae2 Translated using Weblate (Slovenian)
Currently translated at 100.0% (56 of 56 strings)
2016-01-06 09:28:10 +01:00
Mladen Pejaković
367c434010 Translated using Weblate (Serbian)
Currently translated at 100.0% (56 of 56 strings)
2016-01-05 23:54:30 +01:00
chschtsch
02d8463e15 rename resource 2016-01-06 00:02:10 +03:00
Christian Schabesberger
9d5a1d5c43 removed unnececeary comment 2016-01-05 21:54:40 +01:00
Christian Schabesberger
c8d94f541f resolved merge conflict 2016-01-05 21:50:25 +01:00
Christian Schabesberger
27d06eaa6b removed hardcoded string, and add licece to some files. 2016-01-05 21:41:55 +01:00
Christian Schabesberger
7f32857e00 buxfix 2016-01-05 21:23:16 +01:00
chschtsch
2f060f0f52 merging with eb0df2b 2016-01-05 23:16:50 +03:00
chschtsch
f89d405226 merging with eb0df2b 2016-01-05 23:13:52 +03:00
chschtsch
fd4459e570 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-01-05 23:12:22 +03:00
Christian Schabesberger
eb0df2b101 set download path on startup 2016-01-05 21:11:15 +01:00
chschtsch
6c178cfb7e add back missing like button margin 2016-01-05 23:09:15 +03:00
chschtsch
8ced68430d update resources names to match naming convention & cleanup & start working on themes 2016-01-05 22:56:40 +03:00
Aitor Beriain
0aade598ff Translated using Weblate (Basque)
Currently translated at 100.0% (53 of 53 strings)
2016-01-04 20:02:01 +01:00
Aitor Beriain
95949fd1ab Translated using Weblate (Basque)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2016-01-04 19:35:11 +01:00
naofum
1a56382112 Translated using Weblate (Japanese)
Currently translated at 100.0% (53 of 53 strings)
2016-01-04 11:51:32 +01:00
Adam Howard
d610e4b19b minor code tweaks to BackgroundPlayer 2016-01-04 01:51:24 +00:00
Adam Howard
fc44d9e36e Merge branch 'master' of github.com:theScrabi/NewPipe 2016-01-04 01:15:33 +00:00
Adam Howard
c07686576a possible fix for expandedView bug in BackgroundPlayer 2016-01-04 01:15:13 +00:00
Weblate
c2400aea4d Merge remote-tracking branch 'origin/master' 2016-01-04 00:11:51 +01:00
Benedikt Geißler
fb4bf0dde4 Translated using Weblate (German)
Currently translated at 98.1% (52 of 53 strings)
2016-01-04 00:11:51 +01:00
Christian Schabesberger
e4f638d1ce Merge branch 'master' of github.com:theScrabi/NewPipe 2016-01-04 00:11:00 +01:00
Christian Schabesberger
5c492c01a1 adjusted orbot support and moved on to 0.7.2 2016-01-04 00:10:51 +01:00
M2ck
f451e11f82 Translated using Weblate (French)
Currently translated at 100.0% (53 of 53 strings)
2016-01-03 20:55:44 +01:00
Adam Howard
95b73f35f7 Merge branch 'master' of github.com:theScrabi/NewPipe 2016-01-03 19:44:13 +00:00
Adam Howard
58147e9e12 removed commented code in BackgroundPlayer 2016-01-03 19:44:04 +00:00
Christian Schabesberger
a8830e2ede preference screen previews set values 2016-01-03 19:55:04 +01:00
Mladen Pejaković
9804bb95cc Translated using Weblate (Serbian)
Currently translated at 100.0% (53 of 53 strings)
2016-01-03 19:12:16 +01:00
Christian Schabesberger
0da1aef763 Merge pull request #136 from eighthave/tor-support-for-all-except-streaming
Tor support for all except streaming
2016-01-03 17:40:02 +01:00
M2ck
0a334804a3 Translated using Weblate (French)
Currently translated at 100.0% (51 of 51 strings)
2016-01-03 16:56:51 +01:00
naofum
94d2f03e9b Translated using Weblate (Japanese)
Currently translated at 100.0% (51 of 51 strings)
2016-01-03 10:31:40 +01:00
Hans-Christoph Steiner
9127f7f0c2 make progress notification for Tor downloader (closes #39) 2016-01-03 00:04:55 +01:00
Hans-Christoph Steiner
0bb0226bc2 download files via Tor when Tor is enabled
DownloadManager does not let you set its proxy or change how it connects to
the internet.  So we have to make a custom one, unfortunately.  This is a
very basic downloader with none of the special sauce that makes the
built-in DownloadManager handy.
2016-01-02 22:47:21 +01:00
Hans-Christoph Steiner
b3a1a5dcc2 Android provides global vars for the actual download directories 2016-01-02 21:53:48 +01:00
Hans-Christoph Steiner
984dd1cc25 checking on "Use Tor" when Orbot is not installed starts install
If the user turns on "Use Tor" and they are missing Orbot, bring them to
the screen to install Tor.
2016-01-02 21:21:34 +01:00
Hans-Christoph Steiner
5663e543a4 whenever an Activity resumes and tor is enabled, request it start
This makes sure that Orbot is running when the user expects it to be. If
NewPipe is configured to use Tor, then going to a NewPipe screen should
ensure Tor is running.
2016-01-02 21:21:34 +01:00
Hans-Christoph Steiner
d3879a0398 setup Tor at app start, and config immediately when pref is changed
This adds an Application subclass to get the onCreate() method, which is
called once at the first start up of the app, before any Activity starts.
Tor is configured there to ensure it is setup before anything happens.

This also moves the "Use Tor" pref listener to a more appropriate place.
2016-01-02 21:21:34 +01:00
Hans-Christoph Steiner
6bd2468d44 if Orbot is installed, then default to using Tor
If the user has not changed the "Use Tor" preference, then the default
should be to use Tor if Orbot is installed. The user can still override it
by going an unchecking "Use Tor".
2016-01-02 21:21:34 +01:00
Hans-Christoph Steiner
e63d43151b add a title plus summary to "Use Tor" preference 2016-01-02 21:21:33 +01:00
Hans-Christoph Steiner
0265da4ae6 use HttpsURLConnections since youtube.com always uses HTTPS
This helps enforce that the connection is encrypted. If for whatever reason
an unencrypted connection is created, an Exception will be thrown.
2016-01-02 21:21:28 +01:00
GDR!
ef255d12ae Test tor code 2016-01-02 20:22:05 +01:00
Matej U
eeb612f9a2 Translated using Weblate (Slovenian)
Currently translated at 100.0% (51 of 51 strings)
2016-01-02 19:48:51 +01:00
Mladen Pejaković
dfcb4edb81 Translated using Weblate (Serbian)
Currently translated at 100.0% (51 of 51 strings)
2016-01-02 18:04:01 +01:00
Christian Schabesberger
d3500e9036 removed onion routing from readme 2016-01-02 17:41:33 +01:00
Christian Schabesberger
adcb8c6469 add c3s thumbnail and moved on to 0.7.1 2016-01-02 17:40:58 +01:00
Christian Schabesberger
592eee7d3d Merge pull request #134 from eighthave/intent-filters-and-other-fixes
Intent filters and other fixes
2016-01-02 16:18:56 +01:00
Christian Schabesberger
7dadb2b26c fixed close notification problem 2016-01-02 16:08:18 +01:00
Hans-Christoph Steiner
7cbb135f28 include Tibetan as a language option
The Tibetan alphabet was only recently included on Android, so the language
name needs to also have the English there.  Otherwise it'll appear blank
on devices without Tibetan.
2016-01-02 12:15:56 +01:00
Hans-Christoph Steiner
966ac0673c gradle.properties is only commented out defaults, so remove from git
For anyone who tweaks this file for local settings, it becomes painful
to have it committed in git because those changes which are only
relevant to the local setup will show up in git as changed.
2016-01-02 01:35:29 +01:00
Hans-Christoph Steiner
d715eae0d1 route video downloads to "Movies" and audio to "Music"
use the standard Android folders when downloading files.
2016-01-02 01:34:18 +01:00
Hans-Christoph Steiner
ccdd13d136 youtube URLs can also come from media searches and NFC sends 2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
efe5de4c75 support youtube's custom URL schemes (vnd.youtube: and vnd.youtube.launch:) 2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
2a93e9bd2e precisely target these URLs https://www.youtube.com/watch?v=mS1gstS6YS8
These URLs have a Path that always starts with "/watch" so no need for a
pattern.  Also, everything after the "?" is considered the "Query String",
not the Path.  Anything after a "#" is the "Feature String".  The path
matching in IntentFilters only see the Path, and nothing from the "Query
String" or "Feature String".

these are the available kinds of URLs:
https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/YouTubeLinks/YouTubeLinks.html
2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
28dd53ae50 support another youtube URL format: https://www.youtube.com/v/mS1gstS6YS8
https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/YouTubeLinks/YouTubeLinks.html
2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
3c1e64d8dc simplify youtube URL IntentFilters
Each <data> elements applies to the whole IntentFilter, so there is no need
to declare the host, scheme, etc. multiple times within a single
IntentFilter.

Also, pathPrefix="/" will match all paths, so it is unnecessary.
2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
4fe3cb2bca use symlinks to provide alternate folders for Hebrew and Indonesian
These two languages must be included twice (iw/he and id/in)

For a full discussion of why, see:
https://gitlab.com/fdroid/fdroidclient/issues/139
https://stackoverflow.com/questions/5074769/cyanogenmod-translate-a-project/8470980#8470980
https://stackoverflow.com/questions/8393771/android-not-using-finding-my-hebrew-localization

I included a blank placeholder file for Indonesian, it can be simply
replaced by the real one, whenever that comes along.
2016-01-02 00:15:27 +01:00
Hans-Christoph Steiner
b31490c4e3 make all strings translatable 2016-01-02 00:14:35 +01:00
Hans-Christoph Steiner
5533f6ba86 use the standard "Movies" folder for downloads
On all of the devices that I've checked, there is a folder called "Movies"
on the SD Card by default.  NewPipe should use that standard location
since it is always downloading movies :).  People can always change that
via the preferences.

Also, this makes the defaults the same when creating the dir and when
setting the destination URL.
2016-01-02 00:14:11 +01:00
Weblate
8aa5f87a1c Merge remote-tracking branch 'origin/master' 2016-01-01 15:47:36 +01:00
Greg
6deb674377 Translated using Weblate (Hebrew)
Currently translated at 16.6% (8 of 48 strings)
2016-01-01 15:47:36 +01:00
Christian Schabesberger
12d1d998a3 Merge pull request #133 from eighthave/panic-button-support
allow "panic button" apps to wipe activity
2016-01-01 15:47:32 +01:00
Christian Schabesberger
d90162d06f ugly workaround for GEMA test failing 2016-01-01 15:43:06 +01:00
Christian Schabesberger
97c924341c inital YoutubeExtractor test 2016-01-01 15:26:03 +01:00
Hans-Christoph Steiner
e91fc225e1 after receiving panic trigger, quit remove from history
This makes the app fully exit, and removes it from the Recent Apps listing
with the goal of hiding whatever the user was currently watching, and/or
searching for.

PanicKit provides a common framework for creating "panic button" apps that
can trigger actions in "panic responder" apps.  In this case, the response
is to lock the app, if it has been configured to do so

https://dev.guardianproject.info/projects/panic/wiki
2015-12-31 21:53:14 +01:00
M2ck
43149fd832 Translated using Weblate (French)
Currently translated at 100.0% (48 of 48 strings)
2015-12-31 10:27:52 +01:00
Greg
78df579703 Translated using Weblate (Hebrew)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2015-12-29 21:45:44 +01:00
Greg
f61b915894 Translated using Weblate (Russian)
Currently translated at 100.0% (48 of 48 strings)
2015-12-29 21:45:08 +01:00
Christian Schabesberger
cd3f405bff slightly improved YoutubeSearchEngineTest 2015-12-29 21:41:10 +01:00
Christian Schabesberger
7cfdca7a81 remove failing test again 2015-12-29 21:28:27 +01:00
Christian Schabesberger
216063dba8 test if CI failes on failing test 2015-12-29 21:16:18 +01:00
Christian Schabesberger
b647bacd72 add testcase for YoutubeSearchEngine 2015-12-29 21:05:02 +01:00
Christian Schabesberger
4f77937e3e Merge pull request #131 from chschtsch/refactor
refactor localization
2015-12-29 19:14:55 +01:00
chschtsch
48e299b2ac code cleanup 2015-12-29 17:53:24 +03:00
chschtsch
40f00af196 refactor localization 2015-12-29 17:35:51 +03:00
Christian Schabesberger
bd6cc22e63 small hacky error handling refactoring, and add link to c3s 2015-12-28 00:32:38 +01:00
naofum
8760792426 Translated using Weblate (Japanese)
Currently translated at 100.0% (48 of 48 strings)
2015-12-26 12:33:33 +01:00
Christian Schabesberger
870b0bf7aa Merge pull request #127 from 912d/download-directory
Added visible notification after succesful download
2015-12-25 21:27:45 +01:00
Jacek Musiał
afd0bd4318 Added visible notification after succesful downloads
After succesful download, notification will stay in notification bar. I
used "VISIBILITY_VISIBLE_NOTIFY_COMPLETED"  key.
2015-12-25 19:28:09 +01:00
Jacek Musiał
f829ac1d34 Merge remote-tracking branch 'refs/remotes/theScrabi/master' into download-directory 2015-12-25 19:25:13 +01:00
Christian Schabesberger
86a0177855 Merge pull request #126 from Adam77Root/master
Fix view count parsing for large numbers
2015-12-25 16:02:10 +01:00
Adam77Root
718d4fd0bd Fix view count parsing for large numbers 2015-12-25 15:03:11 +01:00
Mladen Pejaković
365137c32b Translated using Weblate (Serbian)
Currently translated at 100.0% (48 of 48 strings)
2015-12-25 00:22:26 +01:00
Christian Schabesberger
e83ca0dfda some improvements for background player 2015-12-25 00:09:35 +01:00
Christian Schabesberger
6a9f6ef651 Merge pull request #123 from 912d/download-directory
Added check if directory exist and try create it
2015-12-23 23:20:42 +01:00
Jacek Musiał
99122ccc03 added check if directory exist and try create it
Also I added new variable `'final File dir`' with value of key
"download_path_preference" or externalStorageDirectory.
Firstly I check if dir exits, then eventually try to create it and next
- download file.
2015-12-23 17:52:01 +01:00
Christian Schabesberger
97923697e1 fixed small writing erros in the README 2015-12-23 14:31:57 +01:00
Greg
68888b15e0 Merge pull request #121 from chschtsch/master
fix sw600dp-land layout problem (#120)
2015-12-23 13:53:42 +03:00
Greg
f48b26067b Update README.md 2015-12-23 11:31:14 +03:00
Greg
4bf2d5837d Update and rename contributing.md to CONTRIBUTING.md 2015-12-23 11:31:11 +03:00
Weblate
4eb2d09c75 Merge remote-tracking branch 'origin/master' 2015-12-22 19:39:49 +01:00
Jack Musial
a146c1c4b6 Translated using Weblate (Polish)
Currently translated at 100.0% (47 of 47 strings)
2015-12-22 19:39:48 +01:00
Sorry Keep Me Anonymous
2f1ea9aa5d Translated using Weblate (Dutch)
Currently translated at 97.8% (46 of 47 strings)
2015-12-22 19:39:48 +01:00
Greg
a90da62deb Merge pull request #122 from rrooij/contributing_guidelines
Add contribution guidelines
2015-12-22 21:39:45 +03:00
Jack Musial
c1c3fbdf26 Translated using Weblate (Polish)
Currently translated at 100.0% (47 of 47 strings)
2015-12-22 18:50:33 +01:00
rrooij
e07a824d82 Add contribution guidelines
Contribution guidelines are a helpful way to inform new potential
contributors about the way in which they can help with the project.

It's also a helpful way to enforce some consistent coding style and
quality among the contributions.
2015-12-22 16:14:56 +01:00
chschtsch
2aff660a5b fix sw600dp-land layout problem (#120) 2015-12-22 15:11:28 +03:00
Weblate
abfcbe6f0e Merge remote-tracking branch 'origin/master' 2015-12-21 22:04:25 +01:00
Matej U
28bf72ed75 Translated using Weblate (Slovenian)
Currently translated at 100.0% (47 of 47 strings)
2015-12-21 22:04:25 +01:00
naofum
21b054d4ca Translated using Weblate (Japanese)
Currently translated at 100.0% (47 of 47 strings)
2015-12-21 22:04:25 +01:00
Greg
34f115b322 remove broken screenshot links 2015-12-22 00:04:22 +03:00
naofum
8b67354076 Translated using Weblate (Japanese)
Currently translated at 100.0% (47 of 47 strings)
2015-12-21 16:20:39 +01:00
M2ck
b62e0a8b40 Translated using Weblate (French)
Currently translated at 100.0% (47 of 47 strings)
2015-12-21 14:20:07 +01:00
Matej U
f46d5376fe Translated using Weblate (Slovenian)
Currently translated at 100.0% (47 of 47 strings)
2015-12-21 13:39:59 +01:00
Matej U
dc3640578f Translated using Weblate (Slovenian)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2015-12-21 13:07:59 +01:00
Sérgio Marques
0a43494de5 Translated using Weblate (Portuguese)
Currently translated at 100.0% (47 of 47 strings)
2015-12-20 22:46:22 +01:00
Sérgio Marques
2544e45d2d Translated using Weblate (Portuguese)
Currently translated at 100% (0 of 0 strings)

Created new translation.
2015-12-20 22:37:30 +01:00
Mladen Pejaković
4a53e9e018 Translated using Weblate (Serbian)
Currently translated at 100.0% (47 of 47 strings)
2015-12-20 22:21:12 +01:00
Christian Schabesberger
9d7dc99416 Update README.md 2015-12-20 21:32:37 +01:00
Christian Schabesberger
c89dc4ba5b setup for version 0.7.0 2015-12-20 21:28:07 +01:00
Christian Schabesberger
72289ced39 Merge branch 'backgroundPlayback' 2015-12-20 18:16:28 +01:00
Christian Schabesberger
3554ccde05 small adjustment before merg 2015-12-20 18:15:48 +01:00
Christian Schabesberger
73e2c42931 Merge pull request #118 from joshsoftware/master
Adding the loading screen when user scroll through videoList.
2015-12-20 13:35:10 +01:00
Christian Schabesberger
b11778ec55 some post changes on the can't play fix. 2015-12-20 13:33:39 +01:00
Christian Schabesberger
18bc937958 fixed "Can't play this video." bug. 2015-12-20 13:26:12 +01:00
Christian Schabesberger
9f618f6678 fixed loding circle for android5+ 2015-12-20 12:48:06 +01:00
Christian Schabesberger
0c3c7493de second try of fixing the failing build 2015-12-20 02:21:14 +01:00
Christian Schabesberger
8f3f02e9f7 Update .travis.yml 2015-12-20 02:13:42 +01:00
Adam Howard
69903ba889 added preference to switch between external and internal audio players 2015-12-20 00:31:31 +00:00
Adam Howard
25c5f95ad9 added white play button icon for notification controls; pause button soon to follow.
Some checks for audioStreams being null added, along with minor semnatic restructuring of parseDashManifest()
2015-12-20 00:08:12 +00:00
Sanjiv Jha
2546d1107e Merge branch 'master' of github.com:joshsoftware/NewPipe 2015-12-19 20:19:19 +05:30
Sanjiv Jha
fdbeaf8692 Added loading footer on paginate screen 2015-12-19 20:18:28 +05:30
naofum
63c0316af2 Translated using Weblate (Japanese)
Currently translated at 100.0% (46 of 46 strings)
2015-12-18 17:10:36 +01:00
Adam Howard
f2e761c07c added reacquisition of CPU lock after resuming 2015-12-17 18:27:35 +00:00
Adam Howard
6a741de7d1 removed commented-out example code 2015-12-17 18:04:18 +00:00
Adam Howard
3e94d18fe1 removed accidental 'git merge' command from manifest 2015-12-17 18:01:24 +00:00
Adam Howard
95d3651e29 Merge branch 'master' of github.com:theScrabi/NewPipe
Conflicts:
	app/src/main/AndroidManifest.xml
2015-12-17 17:53:54 +00:00
Adam Howard
cd2d88781a implemented play/pause and cancel controls 2015-12-17 17:49:12 +00:00
Shekhar Sahu
2178e86d09 Merge branch 'master' of github.com:theScrabi/NewPipe 2015-12-16 14:58:28 +05:30
Shekhar Sahu
df01f41980 Merge branch 'master' of github.com:theScrabi/NewPipe 2015-12-15 17:52:33 +05:30
chschtsch
b0c40d3b09 update cards & update dimens structure 2015-12-15 17:13:43 +05:30
Christian Schabesberger
5880dcbcfd update README.md and readded (still) nececeary assets 2015-12-15 16:49:34 +05:30
Greg
489bbc45f5 Update README.md 2015-12-15 16:49:26 +05:30
chschtsch
5e67502729 add screenshots and new icon 2015-12-15 16:49:25 +05:30
Adam Howard, from my DSABang
26e36454ef merged changes from master 2015-12-03 14:39:51 +00:00
Adam Howard
aebfeb98aa sync so I can clone this branch on another machine 2015-11-29 17:05:44 +00:00
Adam Howard
dc0fc05a9e cleaned up BackgroundPlayer code a little 2015-11-25 17:36:01 +00:00
Adam Howard
6b2c3217ab Implemented a playback notification with a progress bar. No playback controls yet. 2015-11-25 17:18:01 +00:00
Adam Howard
0f93a45b9d reimplemented BackgroundPlayer extending Service, not IntentService. See http://stackoverflow.com/questions/17237746 and http://stackoverflow.com/questions/8690198 2015-11-25 15:19:50 +00:00
Adam Howard
943027ffdd implemented stage 1 ultra-basic background play of videos; see https://github.com/theScrabi/NewPipe/wiki/Background-Playback-Mini-Roadmap 2015-11-24 00:40:36 +00:00
946 changed files with 61842 additions and 5195 deletions

46
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,46 @@
NewPipe contribution guidelines
===============================
PLEASE READ THESE GUIDELINES CAREFULLY BEFORE ANY CONTRIBUTION!
## Crash reporting
Do not report crashes in the GitHub issue tracker. NewPipe has an automated crash report system that will ask you to send a report via e-mail when a crash occurs. This contains all the data we need for debugging, and allows you to even add a comment to it. You'll see exactly what is sent, the system is 100% transparent.
## Issue reporting/feature requests
* Search the [existing issues](https://github.com/TeamNewPipe/NewPipe/issues) first to make sure your issue/feature hasn't been reported/requested before
* Check whether your issue/feature is already fixed/implemented
* Check if the issue still exists in the latest release/beta version
* If you are an Android/Java developer, you are always welcome to fix/implement an issue/a feature yourself. PRs welcome!
* We use English for development. Issues in other languages will be closed and ignored.
* Please only add *one* issue at a time. Do not put multiple issues into one thread.
## Bug Fixing
* If you want to help NewPipe to become free of bugs (this is our utopic goal for NewPipe), you can send us an email to tnp@newpipe.schabi.org to let me know that you intend to help. We'll send you further instructions. You may, on request, register at our [Sentry](https://sentry.schabi.org) instance (see section "Crash reporting" for more information.
## Translation
* NewPipe can be translated via [Weblate](https://hosted.weblate.org/projects/newpipe/strings/). You can log in there with your GitHub account.
## Code contribution
* Stick to NewPipe's style conventions (well, just look the other code and then do it the same way :))
* Do not bring non-free software (e.g., binary blobs) into the project. Also, make sure you do not introduce Google libraries.
* Stick to [F-Droid contribution guidelines](https://f-droid.org/wiki/page/Inclusion_Policy)
* Make changes on a separate branch, not on the master branch. This is commonly known as *feature branch workflow*. You may then send your changes as a pull request on GitHub. Patches to the email address mentioned in this document might not be considered, GitHub is the primary platform.
* When submitting changes, you confirm that your code is licensed under the terms of the [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html).
* Please test (compile and run) your code before you submit changes! Ideally, provide test feedback in the PR description. Untested code will **not** be merged!
* Try to figure out yourself why builds on our CI fail.
* Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job, but if not, you are asked to merge the master branch manually and resolve the problems on your own. That will make the maintainers' jobs way easier.
* Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again about submission, or clearly state that in the description of your PR.
* Respond yourselves if someone requests changes or otherwise raises issues about your PRs.
* Check if your contributions align with the [fdroid inclusion guidelines](https://f-droid.org/en/docs/Inclusion_Policy/).
* Check if your submission can be build with the current fdroid build server setup.
## Communication
* WE DO NOW HAVE A MAILING LIST: [newpipe@list.schabi.org](https://list.schabi.org/cgi-bin/mailman/listinfo/newpipe).
* There is an IRC channel on Freenode which is regularly visited by the core team and other developers: [#newpipe](irc:irc.freenode.net/newpipe). [Click here for Webchat](https://webchat.freenode.net/?channels=newpipe)!
* If you want to get in touch with the core team or one of our other contributors you can send an email to tnp(at)schabi.org. Please do not send issue reports, they will be ignored and remain unanswered! Use the GitHub issue tracker described above!
* Feel free to post suggestions, changes, ideas etc. on GitHub, IRC or the mailing list!

2
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,2 @@
- [ ] I carefully read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.
- [ ] I checked if the issue/feature exists in the latest version.

1
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1 @@
- [ ] I carefully read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.

4
.gitignore vendored
View File

@@ -7,3 +7,7 @@
/app/app.iml
/.idea
/*.iml
gradle.properties
*~
.weblate
*.class

0
.gitmodules vendored Normal file
View File

View File

@@ -1,29 +1,18 @@
language: android
jdk:
- oraclejdk8
android:
components:
# The BuildTools version used by NewPipe
- build-tools-23.0.2
- tools
- build-tools-27.0.3
# The SDK version used to compile NewPipe
- android-23
- android-27
# Additional components
- extra-android-support
- extra-android-m2repository
before_install:
- yes | sdkmanager "platforms;android-27"
script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest
# Emulators
- sys-img-armeabi-v7a-android-21
- sys-img-armeabi-v7a-android-19
- sys-img-armeabi-v7a-android-15
env:
global:
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
matrix:
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
before_script:
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
licenses:
- '.+'

Binary file not shown.

170
CheckTranslations.java Normal file
View File

@@ -0,0 +1,170 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.*;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.nio.file.Files;
import java.nio.charset.Charset;
public final class CheckTranslations {
private static boolean debug = false;
private static boolean plurals = false;
private static boolean empty = false;
private static boolean remove = false;
private static int checks = 0;
private static int matches = 0;
private static int changes = 0;
private static Pattern p, pb, pe, e, o;
/**
* Search translated strings.xml files for empty item / plural tags
* and remove them.
* @param args directories which contain string.xml files (in any subdirectory)
* -e option to find all empty string tags
* -p option to find all empty plurals and item tags
* -r option to remove all occurrences from the files
* -d option to see more details
*/
public static void main(String[] args) {
if (args.length < 1 || (args[0].equals("-d") && args.length < 2)) {
System.out.println("Not enough arguments");
return;
}
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case "-d":
debug = true;
break;
case "-p":
plurals = true;
break;
case "-e":
empty = true;
break;
case "-r":
remove = true;
break;
}
}
if (!plurals && !empty) {
plurals = true;
empty = true;
}
p = Pattern.compile("(<item quantity=\")(zero|one|two|three|few|many|other)(\"></item>|\"/>)");
pb = Pattern.compile("(<plurals[\\sa-zA-Z=\"]*>)");
pe = Pattern.compile("(</plurals>)");
e = Pattern.compile("(<string[\\sa-z_\\\"=]*)((><\\/string>|\\/>){1})");
o = Pattern.compile("(<item quantity=\"other\">)[^</>]*(<\\/item>)");
for (int i = 0; i < args.length; i++) {
if (!args[i].equals("-d") && !args[i].equals("-p") && !args[i].equals("-e") && !args[i].equals("-r")) {
File f = new File(args[i]);
if (f.exists() && !f.isDirectory()) {
checkFile(f);
} else if (f.isDirectory()) {
checkFiles(f.listFiles());
} else {
System.out.println("'" + args[i] + "' does not exist!");
}
}
}
System.out.println(checks + " files were checked.");
System.out.println(matches + " corrupt lines detected.");
if (remove) {
System.out.println(matches + " corrupt lines removed and " + changes + " lines fixed.");
}
}
private static void checkFiles(File[] f) {
for (int i = 0; i < f.length; i++) {
if (f[i].exists() && !f[i].isDirectory()) {
if (f[i].toString().contains("strings.xml")) {
checkFile(f[i]);
}
} else if (f[i].isDirectory()) {
checkFiles(f[i].listFiles());
}
}
}
private static void checkFile(File f) {
// Do not check our original English strings to cause no unwanted changes
// Btw. there should not be empty plural/item tags
if (f.toString().contains("values/strings.xml")) {
return;
}
if (debug) System.out.println("Checking " + f.toString());
checks++;
List<String> lines = new ArrayList<String>();
boolean checkFailed = false;
boolean otherDetected = false;
boolean inPlurals = false;
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
String line;
int ln = 0;
while ((line = br.readLine()) != null) {
ln++;
if (plurals && p.matcher(line).find()) {
matches++;
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
checkFailed = true;
} else if (empty && e.matcher(line).find()) {
matches++;
checkFailed = true;
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
} else {
if (remove) lines.add(line);
}
}
br.close();
int pluralsLine = 0;
for (int i = 0; i < lines.size(); i++) {
if (o.matcher(lines.get(i)).find()) {
otherDetected = true;
}
if (plurals && pb.matcher(lines.get(i)).find()) {
inPlurals = true;
pluralsLine = i;
} else if (plurals && pe.matcher(lines.get(i)).find()) {
inPlurals = false;
if (!otherDetected) {
boolean b = false;
check: for(int j = pluralsLine; j < i; j++) {
if (lines.get(j).contains("many")) {
b = true;
pluralsLine = j;
break check;
}
}
if (remove && b) {
if (debug) System.out.println(" Line " + (pluralsLine + 1) + " was " + ((remove) ? "changed" : "detected") + ": '" + lines.get(pluralsLine) + "'");
lines.set(pluralsLine, lines.get(pluralsLine).replace("many", "other"));
changes++;
checkFailed = true;
} else if (debug) {
if (debug) System.out.println(" WARNING: Line " + (i + 1) + " - No <item quantity=\"other\"> found!");
}
}
otherDetected = false;
}
}
if (remove && checkFailed) {
Files.write(f.toPath(), lines, Charset.forName("UTF-8"));
}
} catch (IOException e) {
System.out.println(e);
}
}
}

106
README.md
View File

@@ -1,24 +1,34 @@
# NewPipe
NewPipe: A free lightweight Youtube frontend for Android.
<p align="center"><a href="https://newpipe.schabi.org"><img src="assets/new_pipe_icon_5.png" width="150"/></a></p>
<h2 align="center"><b>NewPipe</b></h2>
<h4 align="center">A free lightweight YouTube frontend for Android.</h4>
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png"/></a></p>
[![NewPipe](app/src/main/res/mipmap-xhdpi/ic_launcher.png)](http://dasochan.nl/newpipe/)
Project status:
[![Translation Status](https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg)](https://hosted.weblate.org/engage/NewPipe/)
[![Build Status](https://travis-ci.org/theScrabi/NewPipe.svg)](https://travis-ci.org/theScrabi/NewPipe)
## Get NewPipe
[![F-Droid](https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png)](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
<p align="center">
<a href="https://github.com/TeamNewPipe/NewPipe" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" /></a>
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPL v3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg" /></a>
<a href="https://travis-ci.org/TeamNewPipe/NewPipe" alt="Build Status"><img src="https://travis-ci.org/TeamNewPipe/NewPipe.svg" /></a>
<a href="https://hosted.weblate.org/engage/NewPipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg" /></a>
<a href="http://webchat.freenode.net/?channels=%23newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg" /></a>
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"/></a>
</p>
<hr />
<p align="center"><a href="#screenshots">Screenshots</a> &bull; <a href="#description">Description</a> &bull; <a href="#features">Features</a> &bull; <a href="#contribution">Contribution</a> &bull; <a href="#donate">Donate</a> &bull; <a href="#license">License</a></p>
<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 />
WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
## Screenshots
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
[<img src="screenshots/screenshot_2.png" width=150>](screenshots/screenshot_2.png)
[<img src="screenshots/screenshot_3.png" width=150>](screenshots/screenshot_3.png)
[<img src="screenshots/screenshot_4.png" width=150>](screenshots/screenshot_4.png)
[<img src="screenshots/screenshot_5.png" width=150>](screenshots/screenshot_5.png)
[<img src="screenshots/screenshot_6.png" width=250>](screenshots/screenshot_6.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_1.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_1.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_2.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_2.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_3.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_3.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_4.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_4.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_5.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_5.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_6.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_6.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_7.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_7.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
## Description
@@ -29,35 +39,63 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
* Search videos
* Display general information about a video
* Watch YouTube videos
* Listen to YouTube videos (audio only streaming)
* Listen to YouTube videos
* Popup mode (floating player)
* Select the streaming player to watch the video with
* Download videos (working, but it could be better)
* Download audio only (working, but it could be better)
* Download videos
* Download audio only
* Open a video in Kodi
* Show Next/Related videos
* Search YouTube in a specific language
* Watch/Block age restricted material
* Display general information about channels
* Search channels
* Watch videos from a channel
* Orbot/Tor support (not yet directly)
* 1080p/2k/4k support
* View history
* Subscribe to channels
* Search history
* Search/Watch Playlists
* Watch as queues Playlists
* Queuing videos
* Local playlists
* Subtitles
* Multi-service support (eg. SoundCloud in NewPipe Beta)
### Coming Features
* Improved Downloading
* Bookmarks
* View history
* Search history
* Search channels
* Display general information about channels
* Subscribe to channels
* Watch videos from a channel
* Search/Watch Playlists
* Livestream support
* Cast to UPnP and Cast
* Show comments
* ... and many more
### Multiservice support
Although NewPipe only supports YouTube at the moment, it's designed to support many more streaming services. The plan is, that NewPipe will get such support by the version 2.0.
## Contribution
Whether you have ideas, translation, design changes, code cleaning, or real heavy code changes, help is always welcome.
Whether you have ideas, translations, design changes, code cleaning, or real heavy code changes, help is always welcome.
The more is done the better it gets!
Join our [Slack group](http://invite.chschtsch.ml/) if you like to get involved.
If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
## Donate
If you like NewPipe we'd be happy about a donation. You can either donate via Bitcoin, Bountysource or Liberapay. For further information about donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
<table>
<tr>
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin" /></td>
<td><img src="assets/bitcoin_qr_code.png" alt="Bitcoin QR Code" width="100px"/></td>
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
</tr>
<tr>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" /></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"/></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px" /></a></td>
</tr>
<tr>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px" /></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"/></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn." /></a></td>
</tr>
</table>
## License
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)

View File

@@ -1,38 +1,99 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
compileSdkVersion 27
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 23
versionCode 8
versionName "0.6.2"
targetSdkVersion 27
versionCode 60
versionName "0.13.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
multiDexEnabled true
debuggable true
applicationIdSuffix ".debug"
}
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-v4:23.1.1'
compile 'com.android.support:design:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'org.jsoup:jsoup:1.8.3'
compile 'org.mozilla:rhino:1.7.7'
ext {
supportLibVersion = '27.1.0'
exoPlayerLibVersion = '2.7.1'
roomDbLibVersion = '1.0.0'
leakCanaryLibVersion = '1.5.4'
okHttpLibVersion = '1.5.0'
icepickLibVersion = '3.2.0'
stethoLibVersion = '1.5.0'
}
dependencies {
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2') {
exclude module: 'support-annotations'
}
implementation 'com.github.TeamNewPipe:NewPipeExtractor:a6b6235644474'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
implementation "com.android.support:appcompat-v7:$supportLibVersion"
implementation "com.android.support:support-v4:$supportLibVersion"
implementation "com.android.support:design:$supportLibVersion"
implementation "com.android.support:recyclerview-v7:$supportLibVersion"
implementation "com.android.support:preference-v14:$supportLibVersion"
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'ch.acra:acra:4.9.2'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.github.nirhart:ParallaxScroll:dd53d1f9d1'
implementation 'com.nononsenseapps:filepicker:4.2.1'
implementation "com.google.android.exoplayer:exoplayer:$exoPlayerLibVersion"
implementation "com.google.android.exoplayer:extension-mediasession:$exoPlayerLibVersion"
debugImplementation "com.facebook.stetho:stetho:$stethoLibVersion"
debugImplementation "com.facebook.stetho:stetho-urlconnection:$stethoLibVersion"
debugImplementation 'com.android.support:multidex:1.0.3'
implementation 'io.reactivex.rxjava2:rxjava:2.1.10'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation "android.arch.persistence.room:runtime:$roomDbLibVersion"
implementation "android.arch.persistence.room:rxjava2:$roomDbLibVersion"
annotationProcessor "android.arch.persistence.room:compiler:$roomDbLibVersion"
implementation "frankiesardo:icepick:$icepickLibVersion"
annotationProcessor "frankiesardo:icepick-processor:$icepickLibVersion"
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryLibVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryLibVersion"
implementation 'com.squareup.okhttp3:okhttp:3.9.1'
debugImplementation "com.facebook.stetho:stetho-okhttp3:$okHttpLibVersion"
}

View File

@@ -15,3 +15,30 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-dontobfuscate
-keep class org.mozilla.javascript.** { *; }
-keep class org.mozilla.classfile.ClassFileWriter
-keep class com.google.android.exoplayer2.** { *; }
-dontwarn org.mozilla.javascript.tools.**
-dontwarn android.arch.util.paging.CountedDataSource
-dontwarn android.arch.persistence.room.paging.LimitOffsetDataSource
# Rules for icepick. Copy paste from https://github.com/frankiesardo/icepick
-dontwarn icepick.**
-keep class icepick.** { *; }
-keep class **$$Icepick { *; }
-keepclasseswithmembernames class * {
@icepick.* <fields>;
}
-keepnames class * { @icepick.State *;}
# Rules for OkHttp. Copy paste from https://github.com/square/okhttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

View File

@@ -0,0 +1,37 @@
package org.schabi.newpipe.report;
import android.os.Parcel;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.schabi.newpipe.R;
import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
import static org.junit.Assert.assertEquals;
/**
* Instrumented tests for {@link ErrorInfo}
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ErrorInfoTest {
@Test
public void errorInfo_testParcelable() {
ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request", R.string.general_error);
// Obtain a Parcel object and write the parcelable object to it:
Parcel parcel = Parcel.obtain();
info.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
assertEquals("youtube", infoFromParcel.serviceName);
assertEquals("request", infoFromParcel.request);
assertEquals(R.string.general_error, infoFromParcel.message);
parcel.recycle();
}
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.schabi.newpipe">
<application
android:name=".DebugApp"
android:label="NewPipe Debug"
tools:replace="android:name, android:label">
<activity
android:name=".MainActivity"
android:label="NewPipe Debug"
tools:replace="android:label"/>
</application>
</manifest>

View File

@@ -0,0 +1,104 @@
package org.schabi.newpipe;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.multidex.MultiDex;
import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.squareup.leakcanary.AndroidHeapDumper;
import com.squareup.leakcanary.DefaultLeakDirectoryProvider;
import com.squareup.leakcanary.HeapDumper;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.LeakDirectoryProvider;
import com.squareup.leakcanary.RefWatcher;
import org.schabi.newpipe.extractor.Downloader;
import java.io.File;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
public class DebugApp extends App {
private static final String TAG = DebugApp.class.toString();
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
initStetho();
}
@Override
protected Downloader getDownloader() {
return org.schabi.newpipe.Downloader.init(new OkHttpClient.Builder()
.addNetworkInterceptor(new StethoInterceptor()));
}
private void initStetho() {
// Create an InitializerBuilder
Stetho.InitializerBuilder initializerBuilder =
Stetho.newInitializerBuilder(this);
// Enable Chrome DevTools
initializerBuilder.enableWebKitInspector(
Stetho.defaultInspectorModulesProvider(this)
);
// Enable command line interface
initializerBuilder.enableDumpapp(
Stetho.defaultDumperPluginsProvider(getApplicationContext())
);
// Use the InitializerBuilder to generate an Initializer
Stetho.Initializer initializer = initializerBuilder.build();
// Initialize Stetho with the Initializer
Stetho.initialize(initializer);
}
@Override
protected boolean isDisposedRxExceptionsReported() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.allow_disposed_exceptions_key), false);
}
@Override
protected RefWatcher installLeakCanary() {
return LeakCanary.refWatcher(this)
.heapDumper(new ToggleableHeapDumper(this))
// give each object 10 seconds to be gc'ed, before leak canary gets nosy on it
.watchDelay(10, TimeUnit.SECONDS)
.buildAndInstall();
}
public static class ToggleableHeapDumper implements HeapDumper {
private final HeapDumper dumper;
private final SharedPreferences preferences;
private final String dumpingAllowanceKey;
ToggleableHeapDumper(@NonNull final Context context) {
LeakDirectoryProvider leakDirectoryProvider = new DefaultLeakDirectoryProvider(context);
this.dumper = new AndroidHeapDumper(context, leakDirectoryProvider);
this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
this.dumpingAllowanceKey = context.getString(R.string.allow_heap_dumping_key);
}
private boolean isDumpingAllowed() {
return preferences.getBoolean(dumpingAllowanceKey, false);
}
@Override
public File dumpHeap() {
return isDumpingAllowed() ? dumper.dumpHeap() : HeapDumper.RETRY_LATER;
}
}
}

View File

@@ -1,82 +1,240 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.schabi.newpipe" >
package="org.schabi.newpipe">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:logo="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:logo="@mipmap/ic_launcher"
android:theme="@style/OpeningTheme"
tools:ignore="AllowBackup">
<activity
android:name=".VideoItemListActivity"
android:label="@string/app_name">
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<activity
android:name=".VideoItemDetailActivity"
android:label="@string/title_videoitem_detail"
android:theme="@style/AppTheme">
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"/>
<activity
android:name=".player.BackgroundPlayerActivity"
android:launchMode="singleTask"
android:label="@string/title_activity_background_player"/>
<activity
android:name=".player.PopupVideoPlayerActivity"
android:launchMode="singleTask"
android:label="@string/title_activity_popup_player"/>
<service
android:name=".player.PopupVideoPlayer"
android:exported="false"/>
<activity
android:name=".player.MainVideoPlayer"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"/>
<activity
android:name=".settings.SettingsActivity"
android:label="@string/settings"/>
<activity
android:name=".about.AboutActivity"
android:label="@string/title_activity_about"/>
<activity
android:name=".history.HistoryActivity"
android:label="@string/title_activity_history"/>
<service android:name=".subscription.services.SubscriptionsImportService"/>
<service android:name=".subscription.services.SubscriptionsExportService"/>
<activity
android:name=".PanicResponderActivity"
android:launchMode="singleInstance"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".ExitActivity"
android:label="@string/general_error"
android:theme="@android:style/Theme.NoDisplay"/>
<activity android:name=".report.ErrorActivity"/>
<!-- giga get related -->
<activity
android:name=".download.DownloadActivity"
android:label="@string/app_name"
android:launchMode="singleTask"/>
<service android:name="us.shandian.giga.service.DownloadManagerService"/>
<activity
android:name=".util.FilePickerActivityHelper"
android:label="@string/app_name"
android:theme="@style/FilePickerThemeDark">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ReCaptchaActivity"
android:label="@string/reCaptchaActivity"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".VideoItemListActivity" />
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths"/>
</provider>
<activity
android:name=".RouterActivity"
android:excludeFromRecents="true"
android:label="@string/preferred_player_share_menu_title"
android:taskAffinity=""
android:theme="@style/RouterActivityThemeDark">
<!-- Youtube filter -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data
android:host="youtube.com"
android:scheme="http"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="youtube.com"
android:scheme="https"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="www.youtube.com"
android:scheme="http"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="www.youtube.com"
android:scheme="https"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="m.youtube.com"
android:scheme="http"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="m.youtube.com"
android:scheme="https"
android:pathPattern="/?*#*/*watch"/>
<data
android:host="youtu.be"
android:scheme="https"
android:pathPrefix="/"/>
<data
android:host="youtu.be"
android:scheme="http"
android:pathPrefix="/"/>
<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="youtube.com"/>
<data android:host="m.youtube.com"/>
<data android:host="www.youtube.com"/>
<!-- video prefix -->
<data android:pathPrefix="/v/"/>
<data android:pathPrefix="/embed/"/>
<data android:pathPrefix="/watch"/>
<data android:pathPrefix="/attribution_link"/>
<!-- channel prefix -->
<data android:pathPrefix="/channel/"/>
<data android:pathPrefix="/user/"/>
<!-- playlist prefix -->
<data android:pathPrefix="/playlist"/>
</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="http"/>
<data android:scheme="https"/>
<data android:host="youtu.be"/>
<data android:pathPrefix="/"/>
</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>
<!-- Hooktube 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="hooktube.com"/>
<data android:host="*.hooktube.com"/>
<!-- video prefix -->
<data android:pathPrefix="/v/"/>
<data android:pathPrefix="/embed/"/>
<data android:pathPrefix="/watch"/>
<!-- channel prefix -->
<data android:pathPrefix="/channel/"/>
<data android:pathPrefix="/user/"/>
</intent-filter>
<!-- Soundcloud 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="soundcloud.com"/>
<data android:host="m.soundcloud.com"/>
<data android:host="www.soundcloud.com"/>
<data android:pathPrefix="/"/>
</intent-filter>
<!-- Share filter -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
<activity android:name=".PlayVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/VideoPlayerTheme"
android:parentActivityName=".VideoItemDetailActivity"
tools:ignore="UnusedAttribute">
</activity>
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings" >
</activity>
<service
android:name=".RouterActivity$FetcherService"
android:exported="false"/>
</application>
</manifest>
</manifest>

View File

@@ -0,0 +1,162 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Apache License - Version 2.0, January 2004</title>
</head>
<body>
<p>Apache License<br>Version 2.0, January 2004<br>
<a href="http://www.apache.org/licenses/">http://www.apache.org/licenses/</a> </p>
<p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</p>
<p><strong><a name="definitions">1. Definitions</a></strong>.</p>
<p>"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.</p>
<p>"Licensor" shall mean the copyright owner or entity authorized by the
copyright owner that is granting the License.</p>
<p>"Legal Entity" shall mean the union of the acting entity and all other
entities that control, are controlled by, or are under common control with
that entity. For the purposes of this definition, "control" means (i) the
power, direct or indirect, to cause the direction or management of such
entity, whether by contract or otherwise, or (ii) ownership of fifty
percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.</p>
<p>"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.</p>
<p>"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source,
and configuration files.</p>
<p>"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled
object code, generated documentation, and conversions to other media types.</p>
<p>"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the
Appendix below).</p>
<p>"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial
revisions, annotations, elaborations, or other modifications represent, as
a whole, an original work of authorship. For the purposes of this License,
Derivative Works shall not include works that remain separable from, or
merely link (or bind by name) to the interfaces of, the Work and Derivative
Works thereof.</p>
<p>"Contribution" shall mean any work of authorship, including the original
version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the copyright owner or by an individual or Legal
Entity authorized to submit on behalf of the copyright owner. For the
purposes of this definition, "submitted" means any form of electronic,
verbal, or written communication sent to the Licensor or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that
are managed by, or on behalf of, the Licensor for the purpose of discussing
and improving the Work, but excluding communication that is conspicuously
marked or otherwise designated in writing by the copyright owner as "Not a
Contribution."</p>
<p>"Contributor" shall mean Licensor and any individual or Legal Entity on
behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.</p>
<p><strong><a name="copyright">2. Grant of Copyright License</a></strong>. Subject to the
terms and conditions of this License, each Contributor hereby grants to You
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, publicly
display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.</p>
<p><strong><a name="patent">3. Grant of Patent License</a></strong>. Subject to the terms
and conditions of this License, each Contributor hereby grants to You a
perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made, use,
offer to sell, sell, import, and otherwise transfer the Work, where such
license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by
combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
that the Work or a Contribution incorporated within the Work constitutes
direct or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate as of the
date such litigation is filed.</p>
<p><strong><a name="redistribution">4. Redistribution</a></strong>. You may reproduce and
distribute copies of the Work or Derivative Works thereof in any medium,
with or without modifications, and in Source or Object form, provided that
You meet the following conditions:</p>
<ol style="list-style: lower-latin;">
<li>You must give any other recipients of the Work or Derivative Works a
copy of this License; and</li>
<li>You must cause any modified files to carry prominent notices stating
that You changed the files; and</li>
<li>You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices from
the Source form of the Work, excluding those notices that do not pertain to
any part of the Derivative Works; and</li>
<li>If the Work includes a "NOTICE" text file as part of its distribution,
then any Derivative Works that You distribute must include a readable copy
of the attribution notices contained within such NOTICE file, excluding
those notices that do not pertain to any part of the Derivative Works, in
at least one of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or documentation,
if provided along with the Derivative Works; or, within a display generated
by the Derivative Works, if and wherever such third-party notices normally
appear. The contents of the NOTICE file are for informational purposes only
and do not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an addendum to
the NOTICE text from the Work, provided that such additional attribution
notices cannot be construed as modifying the License.
<br/>
<br/>
You may add Your own copyright statement to Your modifications and may
provide additional or different license terms and conditions for use,
reproduction, or distribution of Your modifications, or for any such
Derivative Works as a whole, provided Your use, reproduction, and
distribution of the Work otherwise complies with the conditions stated in
this License.
</li>
</ol>
<p><strong><a name="contributions">5. Submission of Contributions</a></strong>. Unless You
explicitly state otherwise, any Contribution intentionally submitted for
inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the
terms of any separate license agreement you may have executed with Licensor
regarding such Contributions.</p>
<p><strong><a name="trademarks">6. Trademarks</a></strong>. This License does not grant
permission to use the trade names, trademarks, service marks, or product
names of the Licensor, except as required for reasonable and customary use
in describing the origin of the Work and reproducing the content of the
NOTICE file.</p>
<p><strong><a name="no-warranty">7. Disclaimer of Warranty</a></strong>. Unless required by
applicable law or agreed to in writing, Licensor provides the Work (and
each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You
are solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise
of permissions under this License.</p>
<p><strong><a name="no-liability">8. Limitation of Liability</a></strong>. In no event and
under no legal theory, whether in tort (including negligence), contract, or
otherwise, unless required by applicable law (such as deliberate and
grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a result
of this License or out of the use or inability to use the Work (including
but not limited to damages for loss of goodwill, work stoppage, computer
failure or malfunction, or any and all other commercial damages or losses),
even if such Contributor has been advised of the possibility of such
damages.</p>
<p><strong><a name="additional">9. Accepting Warranty or Additional Liability</a></strong>.
While redistributing the Work or Derivative Works thereof, You may choose
to offer, and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this License.
However, in accepting such obligations, You may act only on Your own behalf
and on Your sole responsibility, not on behalf of any other Contributor,
and only if You agree to indemnify, defend, and hold each Contributor
harmless for any liability incurred by, or claims asserted against, such
Contributor by reason of your accepting any such warranty or additional
liability.</p>
</body>
</html>

View File

@@ -0,0 +1,400 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>GNU General Public License v2.0 - GNU Project - Free Software Foundation (FSF)</title>
<link rel="alternate" type="application/rdf+xml"
href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.rdf" />
</head>
<body>
<h3><a id="SEC1">GNU GENERAL PUBLIC LICENSE</a></h3>
<p>
Version 2, June 1991
</p>
<pre>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.<br/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA<br/>
<br/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
</pre>
<h3 id="preamble"><a id="SEC2">Preamble</a></h3>
<p>
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
</p>
<p>
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
</p>
<p>
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
</p>
<p>
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
</p>
<p>
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
</p>
<p>
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
</p>
<p>
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
</p>
<p>
The precise terms and conditions for copying, distribution and
modification follow.
</p>
<h3 id="terms"><a id="SEC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</a></h3>
<p id="section0">
<strong>0.</strong>
This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
</p>
<p>
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
</p>
<p id="section1">
<strong>1.</strong>
You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
</p>
<p>
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
</p>
<p id="section2">
<strong>2.</strong>
You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
</p>
<dl>
<dt></dt>
<dd>
<strong>a)</strong>
You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
</dd>
<dt></dt>
<dd>
<strong>b)</strong>
You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
</dd>
<dt></dt>
<dd>
<strong>c)</strong>
If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
</dd>
</dl>
<p>
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
</p>
<p>
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
</p>
<p>
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
</p>
<p id="section3">
<strong>3.</strong>
You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
</p>
<!-- we use this doubled UL to get the sub-sections indented, -->
<!-- while making the bullets as unobvious as possible. -->
<dl>
<dt></dt>
<dd>
<strong>a)</strong>
Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
</dd>
<dt></dt>
<dd>
<strong>b)</strong>
Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
</dd>
<dt></dt>
<dd>
<strong>c)</strong>
Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
</dd>
</dl>
<p>
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major softwareComponents (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
</p>
<p>
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
</p>
<p id="section4">
<strong>4.</strong>
You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
</p>
<p id="section5">
<strong>5.</strong>
You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
</p>
<p id="section6">
<strong>6.</strong>
Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
</p>
<p id="section7">
<strong>7.</strong>
If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
</p>
<p>
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
</p>
<p>
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
</p>
<p>
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
</p>
<p id="section8">
<strong>8.</strong>
If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
</p>
<p id="section9">
<strong>9.</strong>
The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
</p>
<p>
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
</p>
<p id="section10">
<strong>10.</strong>
If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
</p>
<p id="section11"><strong>NO WARRANTY</strong></p>
<p>
<strong>11.</strong>
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
</p>
<p id="section12">
<strong>12.</strong>
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
</p>
</body></html>

View File

@@ -0,0 +1,639 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>GNU General Public License v3.0 - GNU Project - Free Software Foundation (FSF)</title>
<link rel="alternate" type="application/rdf+xml"
href="http://www.gnu.org/licenses/gpl-3.0.rdf" />
</head>
<body>
<h3 style="text-align: center;">GNU GENERAL PUBLIC LICENSE</h3>
<p style="text-align: center;">Version 3, 29 June 2007</p>
<p>Copyright &copy; 2007 Free Software Foundation, Inc.
&lt;<a href="http://fsf.org/">http://fsf.org/</a>&gt;</p><p>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.</p>
<h3><a name="preamble"></a>Preamble</h3>
<p>The GNU General Public License is a free, copyleft license for
software and other kinds of works.</p>
<p>The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.</p>
<p>When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.</p>
<p>To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.</p>
<p>For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.</p>
<p>Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.</p>
<p>For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.</p>
<p>Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.</p>
<p>Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.</p>
<p>The precise terms and conditions for copying, distribution and
modification follow.</p>
<h3><a name="terms"></a>TERMS AND CONDITIONS</h3>
<h4><a name="section0"></a>0. Definitions.</h4>
<p>&ldquo;This License&rdquo; refers to version 3 of the GNU General Public License.</p>
<p>&ldquo;Copyright&rdquo; also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.</p>
<p>&ldquo;The Program&rdquo; refers to any copyrightable work licensed under this
License. Each licensee is addressed as &ldquo;you&rdquo;. &ldquo;Licensees&rdquo; and
&ldquo;recipients&rdquo; may be individuals or organizations.</p>
<p>To &ldquo;modify&rdquo; a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a &ldquo;modified version&rdquo; of the
earlier work or a work &ldquo;based on&rdquo; the earlier work.</p>
<p>A &ldquo;covered work&rdquo; means either the unmodified Program or a work based
on the Program.</p>
<p>To &ldquo;propagate&rdquo; a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.</p>
<p>To &ldquo;convey&rdquo; a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.</p>
<p>An interactive user interface displays &ldquo;Appropriate Legal Notices&rdquo;
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.</p>
<h4><a name="section1"></a>1. Source Code.</h4>
<p>The &ldquo;source code&rdquo; for a work means the preferred form of the work
for making modifications to it. &ldquo;Object code&rdquo; means any non-source
form of a work.</p>
<p>A &ldquo;Standard Interface&rdquo; means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.</p>
<p>The &ldquo;System Libraries&rdquo; of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
&ldquo;Major Component&rdquo;, in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.</p>
<p>The &ldquo;Corresponding Source&rdquo; for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.</p>
<p>The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.</p>
<p>The Corresponding Source for a work in source code form is that
same work.</p>
<h4><a name="section2"></a>2. Basic Permissions.</h4>
<p>All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.</p>
<p>You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.</p>
<p>Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.</p>
<h4><a name="section3"></a>3. Protecting Users' Legal Rights From Anti-Circumvention Law.</h4>
<p>No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.</p>
<p>When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.</p>
<h4><a name="section4"></a>4. Conveying Verbatim Copies.</h4>
<p>You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.</p>
<p>You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.</p>
<h4><a name="section5"></a>5. Conveying Modified Source Versions.</h4>
<p>You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:</p>
<ul>
<li>a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.</li>
<li>b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
&ldquo;keep intact all notices&rdquo;.</li>
<li>c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.</li>
<li>d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.</li>
</ul>
<p>A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
&ldquo;aggregate&rdquo; if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.</p>
<h4><a name="section6"></a>6. Conveying Non-Source Forms.</h4>
<p>You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:</p>
<ul>
<li>a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.</li>
<li>b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.</li>
<li>c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.</li>
<li>d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.</li>
<li>e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.</li>
</ul>
<p>A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.</p>
<p>A &ldquo;User Product&rdquo; is either (1) a &ldquo;consumer product&rdquo;, which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, &ldquo;normally used&rdquo; refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.</p>
<p>&ldquo;Installation Information&rdquo; for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.</p>
<p>If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).</p>
<p>The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.</p>
<p>Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.</p>
<h4><a name="section7"></a>7. Additional Terms.</h4>
<p>&ldquo;Additional permissions&rdquo; are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.</p>
<p>When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.</p>
<p>Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:</p>
<ul>
<li>a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or</li>
<li>b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or</li>
<li>c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or</li>
<li>d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or</li>
<li>e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or</li>
<li>f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.</li>
</ul>
<p>All other non-permissive additional terms are considered &ldquo;further
restrictions&rdquo; within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.</p>
<p>If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.</p>
<p>Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.</p>
<h4><a name="section8"></a>8. Termination.</h4>
<p>You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).</p>
<p>However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.</p>
<p>Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.</p>
<p>Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.</p>
<h4><a name="section9"></a>9. Acceptance Not Required for Having Copies.</h4>
<p>You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.</p>
<h4><a name="section10"></a>10. Automatic Licensing of Downstream Recipients.</h4>
<p>Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.</p>
<p>An &ldquo;entity transaction&rdquo; is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.</p>
<p>You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.</p>
<h4><a name="section11"></a>11. Patents.</h4>
<p>A &ldquo;contributor&rdquo; is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's &ldquo;contributor version&rdquo;.</p>
<p>A contributor's &ldquo;essential patent claims&rdquo; are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, &ldquo;control&rdquo; includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.</p>
<p>Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.</p>
<p>In the following three paragraphs, a &ldquo;patent license&rdquo; is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To &ldquo;grant&rdquo; such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.</p>
<p>If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. &ldquo;Knowingly relying&rdquo; means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.</p>
<p>If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.</p>
<p>A patent license is &ldquo;discriminatory&rdquo; if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.</p>
<p>Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.</p>
<h4><a name="section12"></a>12. No Surrender of Others' Freedom.</h4>
<p>If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.</p>
<h4><a name="section13"></a>13. Use with the GNU Affero General Public License.</h4>
<p>Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.</p>
<h4><a name="section14"></a>14. Revised Versions of this License.</h4>
<p>The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.</p>
<p>Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License &ldquo;or any later version&rdquo; applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.</p>
<p>If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.</p>
<p>Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.</p>
<h4><a name="section15"></a>15. Disclaimer of Warranty.</h4>
<p>THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &ldquo;AS IS&rdquo; WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</p>
<h4><a name="section16"></a>16. Limitation of Liability.</h4>
<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.</p>
<h4><a name="section17"></a>17. Interpretation of Sections 15 and 16.</h4>
<p>If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.</p>
</body></html>

View File

@@ -0,0 +1,26 @@
<html>
<head></head>
<body>
<p>Copyright (c) &lt;year&gt; &lt;copyright holders&gt;</p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:</p>
<p>
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.<br />
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
</body>
</html>

View File

@@ -0,0 +1,261 @@
<!DOCTYPE html>
<!-- saved from url=(0038)https://www.mozilla.org/en-US/MPL/2.0/ -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mozilla Public License, version 2.0</title>
</head>
<body>
<h1 id="mozilla-public-license-version-2.0">Mozilla Public License<br>Version 2.0</h1>
<h2 id="definitions">1. Definitions</h2>
<dl>
<dt>1.1. “Contributor”</dt>
<dd><p>means each individual or legal entity that creates, contributes to the creation of, or
owns Covered Software.</p>
</dd>
<dt>1.2. “Contributor Version”</dt>
<dd><p>means the combination of the Contributions of others (if any) used by a Contributor and
that particular Contributors Contribution.</p>
</dd>
<dt>1.3. “Contribution”</dt>
<dd><p>means Covered Software of a particular Contributor.</p>
</dd>
<dt>1.4. “Covered Software”</dt>
<dd><p>means Source Code Form to which the initial Contributor has attached the notice in
Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source
Code Form, in each case including portions thereof.</p>
</dd>
<dt>1.5. “Incompatible With Secondary Licenses”</dt>
<dd><p>means</p>
<ol type="a">
<li><p>that the initial Contributor has attached the notice described in Exhibit B to
the Covered Software; or</p></li>
<li><p>that the Covered Software was made available under the terms of version 1.1 or
earlier of the License, but not also under the terms of a Secondary License.</p>
</li>
</ol>
</dd>
<dt>1.6. “Executable Form”</dt>
<dd><p>means any form of the work other than Source Code Form.</p>
</dd>
<dt>1.7. “Larger Work”</dt>
<dd><p>means a work that combines Covered Software with other material, in a separate file or
files, that is not Covered Software.</p>
</dd>
<dt>1.8. “License”</dt>
<dd><p>means this document.</p>
</dd>
<dt>1.9. “Licensable”</dt>
<dd><p>means having the right to grant, to the maximum extent possible, whether at the time of
the initial grant or subsequently, any and all of the rights conveyed by this License.</p>
</dd>
<dt>1.10. “Modifications”</dt>
<dd><p>means any of the following:</p>
<ol type="a">
<li><p>any file in Source Code Form that results from an addition to, deletion from, or
modification of the contents of Covered Software; or</p></li>
<li><p>any new file in Source Code Form that contains any Covered Software.</p></li>
</ol>
</dd>
<dt>1.11. “Patent Claims” of a Contributor</dt>
<dd><p>means any patent claim(s), including without limitation, method, process, and apparatus
claims, in any patent Licensable by such Contributor that would be infringed, but for the
grant of the License, by the making, using, selling, offering for sale, having made, import,
or transfer of either its Contributions or its Contributor Version.</p>
</dd>
<dt>1.12. “Secondary License”</dt>
<dd><p>means either the GNU General Public License, Version 2.0, the GNU Lesser General Public
License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later
versions of those licenses.</p>
</dd>
<dt>1.13. “Source Code Form”</dt>
<dd><p>means the form of the work preferred for making modifications.</p>
</dd>
<dt>1.14. “You” (or “Your”)</dt>
<dd><p>means an individual or a legal entity exercising rights under this License. For legal
entities, “You” includes any entity that controls, is controlled by, or is under common
control with You. For purposes of this definition, “control” means (a) the power, direct or
indirect, to cause the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or
beneficial ownership of such entity.</p>
</dd>
</dl>
<h2 id="license-grants-and-conditions">2. License Grants and Conditions</h2>
<h3 id="grants">2.1. Grants</h3>
<p>Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:</p>
<ol type="a">
<li><p>under intellectual property rights (other than patent or trademark) Licensable by such
Contributor to use, reproduce, make available, modify, display, perform, distribute, and
otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and</p></li>
<li><p>under Patent Claims of such Contributor to make, use, sell, offer for sale, have made,
import, and otherwise transfer either its Contributions or its Contributor Version.</p></li>
</ol>
<h3 id="effective-date">2.2. Effective Date</h3>
<p>The licenses granted in Section&nbsp;2.1 with respect to any Contribution become effective for
each Contribution on the date the Contributor first distributes such Contribution.</p>
<h3 id="limitations-on-grant-scope">2.3. Limitations on Grant Scope</h3>
<p>The licenses granted in this Section&nbsp;2 are the only rights granted under this License. No
additional rights or licenses will be implied from the distribution or licensing of Covered
Software under this License. Notwithstanding Section&nbsp;2.1(b) above, no patent license is
granted by a Contributor:</p>
<ol type="a">
<li><p>for any code that a Contributor has removed from Covered Software; or</p></li>
<li><p>for infringements caused by: (i) Your and any other third partys modifications of
Covered Software, or (ii) the combination of its Contributions with other software (except
as part of its Contributor Version); or</p></li>
<li><p>under Patent Claims infringed by Covered Software in the absence of its
Contributions.</p></li>
</ol>
<p>This License does not grant any rights in the trademarks, service marks, or logos of any
Contributor (except as may be necessary to comply with the notice requirements in Section&nbsp;3.4).</p>
<h3 id="subsequent-licenses">2.4. Subsequent Licenses</h3>
<p>No Contributor makes additional grants as a result of Your choice to distribute the Covered
Software under a subsequent version of this License (see Section&nbsp;10.2) or under the terms
of a Secondary License (if permitted under the terms of Section&nbsp;3.3).</p>
<h3 id="representation">2.5. Representation</h3>
<p>Each Contributor represents that the Contributor believes its Contributions are its original
creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by
this License.</p>
<h3 id="fair-use">2.6. Fair Use</h3>
<p>This License is not intended to limit any rights You have under applicable copyright doctrines of
fair use, fair dealing, or other equivalents.</p>
<h3 id="conditions">2.7. Conditions</h3>
<p>Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section&nbsp;2.1.</p>
<h2 id="responsibilities">3. Responsibilities</h2>
<h3 id="distribution-of-source-form">3.1. Distribution of Source Form</h3>
<p>All distribution of Covered Software in Source Code Form, including any Modifications that You
create or to which You contribute, must be under the terms of this License. You must inform
recipients that the Source Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients rights in the Source Code Form.</p>
<h3 id="distribution-of-executable-form">3.2. Distribution of Executable Form</h3>
<p>If You distribute Covered Software in Executable Form then:</p>
<ol type="a">
<li><p>such Covered Software must also be made available in Source Code Form, as described in
Section&nbsp;3.1, and You must inform recipients of the Executable Form how they can obtain
a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and</p></li>
<li><p>You may distribute such Executable Form under the terms of this License, or sublicense it
under different terms, provided that the license for the Executable Form does not attempt to
limit or alter the recipients rights in the Source Code Form under this License.</p></li>
</ol>
<h3 id="distribution-of-a-larger-work">3.3. Distribution of a Larger Work</h3>
<p>You may create and distribute a Larger Work under terms of Your choice, provided that You also
comply with the requirements of this License for the Covered Software. If the Larger Work is a
combination of Covered Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this License permits You to
additionally distribute such Covered Software under the terms of such Secondary License(s), so
that the recipient of the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary License(s).</p>
<h3 id="notices">3.4. Notices</h3>
<p>You may not remove or alter the substance of any license notices (including copyright notices,
patent notices, disclaimers of warranty, or limitations of liability) contained within the
Source Code Form of the Covered Software, except that You may alter any license notices to the
extent required to remedy known factual inaccuracies.</p>
<h3 id="application-of-additional-terms">3.5. Application of Additional Terms</h3>
<p>You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Software. However, You may do so only on Your
own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by You alone, and You
hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a
result of warranty, support, indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any jurisdiction.</p>
<h2 id="inability-to-comply-due-to-statute-or-regulation">4. Inability to Comply Due to Statute or
Regulation</h2>
<p>If it is impossible for You to comply with any of the terms of this License with respect to some
or all of the Covered Software due to statute, judicial order, or regulation then You must: (a)
comply with the terms of this License to the maximum extent possible; and (b) describe the
limitations and the code they affect. Such description must be placed in a text file included
with all distributions of the Covered Software under this License. Except to the extent
prohibited by statute or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.</p>
<h2 id="termination">5. Termination</h2>
<p>5.1. The rights granted under this License will terminate automatically if You fail to comply
with any of its terms. However, if You become compliant, then the rights granted under this
License from a particular Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such
Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days
after You have come back into compliance. Moreover, Your grants from a particular Contributor
are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of non-compliance with
this License from such Contributor, and You become compliant prior to 30 days after Your receipt
of the notice.</p>
<p>5.2. If You initiate litigation against any entity by asserting a patent infringement claim
(excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a
Contributor Version directly or indirectly infringes any patent, then the rights granted to You
by any and all Contributors for the Covered Software under Section&nbsp;2.1 of this License
shall terminate.</p>
<p>5.3. In the event of termination under Sections&nbsp;5.1 or 5.2 above, all end user license
agreements (excluding distributors and resellers) which have been validly granted by You or Your
distributors under this License prior to termination shall survive termination.</p>
<h2 id="disclaimer-of-warranty">6. Disclaimer of Warranty</h2>
<p><em>Covered Software is provided under this License on an “as is” basis, without warranty of any
kind, either expressed, implied, or statutory, including, without limitation, warranties that
the Covered Software is free of defects, merchantable, fit for a particular purpose or
non-infringing. The entire risk as to the quality and performance of the Covered Software is
with You. Should any Covered Software prove defective in any respect, You (not any Contributor)
assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty
constitutes an essential part of this License. No use of any Covered Software is authorized
under this License except under this disclaimer.</em></p>
<h2 id="limitation-of-liability">7. Limitation of Liability</h2>
<p><em>Under no circumstances and under no legal theory, whether tort (including negligence),
contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as
permitted above, be liable to You for any direct, indirect, special, incidental, or
consequential damages of any character including, without limitation, damages for lost profits,
loss of goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses, even if such party shall have been informed of the possibility of
such damages. This limitation of liability shall not apply to liability for death or personal
injury resulting from such partys negligence to the extent applicable law prohibits such
limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.</em></p>
<h2 id="litigation">8. Litigation</h2>
<p>Any litigation relating to this License may be brought only in the courts of a jurisdiction where
the defendant maintains its principal place of business and such litigation shall be governed by
laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this
Section shall prevent a partys ability to bring cross-claims or counter-claims.</p>
<h2 id="miscellaneous">9. Miscellaneous</h2>
<p>This License represents the complete agreement concerning the subject matter hereof. If any
provision of this License is held to be unenforceable, such provision shall be reformed only to
the extent necessary to make it enforceable. Any law or regulation which provides that the
language of a contract shall be construed against the drafter shall not be used to construe this
License against a Contributor.</p>
<h2 id="versions-of-the-license">10. Versions of the License</h2>
<h3 id="new-versions">10.1. New Versions</h3>
<p>Mozilla Foundation is the license steward. Except as provided in Section&nbsp;10.3, no one other
than the license steward has the right to modify or publish new versions of this License. Each
version will be given a distinguishing version number.</p>
<h3 id="effect-of-new-versions">10.2. Effect of New Versions</h3>
<p>You may distribute the Covered Software under the terms of the version of the License under which
You originally received the Covered Software, or under the terms of any subsequent version
published by the license steward.</p>
<h3 id="modified-versions">10.3. Modified Versions</h3>
<p>If you create software not governed by this License, and you want to create a new license for
such software, you may create and use a modified version of this License if you rename the
license and remove any references to the name of the license steward (except to note that such
modified license differs from this License).</p>
<h3 id="distributing-source-code-form-that-is-incompatible-with-secondary-licenses">10.4.
Distributing Source Code Form that is Incompatible With Secondary Licenses</h3>
<p>If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under
the terms of this version of the License, the notice described in Exhibit B of this License must
be attached.</p>
<h2 id="exhibit-a---source-code-form-license-notice">Exhibit A - Source Code Form License
Notice</h2>
<blockquote>
<p>This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a
copy of the MPL was not distributed with this file, You can obtain one at
https://mozilla.org/MPL/2.0/.</p>
</blockquote>
<p>If it is not possible or desirable to put the notice in a particular file, then You may include
the notice in a location (such as a LICENSE file in a relevant directory) where a recipient
would be likely to look for such a notice.</p>
<p>You may add additional accurate notices of copyright ownership.</p>
<h2 id="exhibit-b---incompatible-with-secondary-licenses-notice">Exhibit B - “Incompatible With
Secondary Licenses” Notice</h2>
<blockquote>
<p>This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla
Public License, v. 2.0.</p>
</blockquote>
</body>
</html>

View File

@@ -1,329 +0,0 @@
package org.schabi.newpipe;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
/**
* Created by Christian Schabesberger on 18.08.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* DetailsMenuHandler.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/>.
*/
class ActionBarHandler {
private static final String TAG = ActionBarHandler.class.toString();
private static final String KORE_PACKET = "org.xbmc.kore";
private String websiteUrl = "";
private AppCompatActivity activity;
private VideoInfo.VideoStream[] videoStreams = null;
private VideoInfo.AudioStream audioStream = null;
private int selectedStream = -1;
private String videoTitle = "";
private SharedPreferences defaultPreferences = null;
private int startPosition;
@SuppressWarnings("deprecation")
private class FormatItemSelectListener implements ActionBar.OnNavigationListener {
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
selectFormatItem((int)itemId);
return true;
}
}
public ActionBarHandler(AppCompatActivity activity) {
this.activity = activity;
}
@SuppressWarnings({"deprecation", "ConstantConditions"})
public void setupNavMenu(AppCompatActivity activity) {
this.activity = activity;
try {
activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
} catch(NullPointerException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) {
this.videoStreams = videoStreams;
selectedStream = 0;
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
String[] itemArray = new String[videoStreams.length];
String defaultResolution = defaultPreferences
.getString(activity.getString(R.string.defaultResolutionPreference),
activity.getString(R.string.defaultResolutionListItem));
int defaultResolutionPos = 0;
for(int i = 0; i < videoStreams.length; i++) {
itemArray[i] = MediaFormat.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
if(defaultResolution.equals(videoStreams[i].resolution)) {
defaultResolutionPos = i;
}
}
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(activity.getBaseContext(),
android.R.layout.simple_spinner_dropdown_item, itemArray);
if(activity != null) {
ActionBar ab = activity.getSupportActionBar();
assert ab != null : "Could not get actionbar";
ab.setListNavigationCallbacks(itemAdapter
, new FormatItemSelectListener());
ab.setSelectedNavigationItem(defaultResolutionPos);
}
// set audioStream
audioStream = null;
String preferedFormat = defaultPreferences
.getString(activity.getString(R.string.defaultAudioFormatPreference), "webm");
if(preferedFormat.equals("webm")) {
for(VideoInfo.AudioStream s : audioStreams) {
if(s.format == MediaFormat.WEBMA.id) {
audioStream = s;
}
}
} else if(preferedFormat.equals("m4a")){
for(VideoInfo.AudioStream s : audioStreams) {
if(s.format == MediaFormat.M4A.id &&
(audioStream == null || audioStream.bandwidth > s.bandwidth)) {
audioStream = s;
}
}
}
}
private void selectFormatItem(int i) {
selectedStream = i;
}
public void setupMenu(Menu menu, MenuInflater inflater) {
// CAUTION set item properties programmatically otherwise it would not be accepted by
// appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
inflater.inflate(R.menu.videoitem_detail, menu);
MenuItem castItem = menu.findItem(R.id.action_play_with_kodi);
castItem.setVisible(defaultPreferences
.getBoolean(activity.getString(R.string.showPlayWidthKodiPreference), false));
}
public boolean onItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case R.id.menu_item_share:
if(!videoTitle.isEmpty()) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, websiteUrl);
intent.setType("text/plain");
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.shareDialogTitle)));
}
return true;
case R.id.menu_item_openInBrowser: {
openInBrowser();
}
return true;
case R.id.menu_item_download:
downloadVideo();
return true;
case R.id.action_settings: {
Intent intent = new Intent(activity, SettingsActivity.class);
activity.startActivity(intent);
}
break;
case R.id.action_play_with_kodi:
playWithKodi();
return true;
case R.id.menu_item_play_audio:
playAudio();
return true;
default:
Log.e(TAG, "Menu Item not known");
}
return false;
}
public void setVideoInfo(String websiteUrl, String videoTitle) {
this.websiteUrl = websiteUrl;
this.videoTitle = videoTitle;
}
public void playVideo() {
// ----------- THE MAGIC MOMENT ---------------
if(!videoTitle.isEmpty()) {
if (PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(activity.getString(R.string.useExternalPlayer), false)) {
// External Player
Intent intent = new Intent();
try {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(videoStreams[selectedStream].url),
MediaFormat.getMimeById(videoStreams[selectedStream].format));
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
intent.putExtra("title", videoTitle);
activity.startActivity(intent); // HERE !!!
} catch (Exception e) {
e.printStackTrace();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.noPlayerFound)
.setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl)));
activity.startActivity(intent);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.create().show();
}
} else {
// Internal Player
Intent intent = new Intent(activity, PlayVideoActivity.class);
intent.putExtra(PlayVideoActivity.VIDEO_TITLE, videoTitle);
intent.putExtra(PlayVideoActivity.STREAM_URL, videoStreams[selectedStream].url);
intent.putExtra(PlayVideoActivity.VIDEO_URL, websiteUrl);
intent.putExtra(PlayVideoActivity.START_POSITION, startPosition);
activity.startActivity(intent); //also HERE !!!
}
}
// --------------------------------------------
}
public void setStartPosition(int startPositionSeconds)
{
this.startPosition = startPositionSeconds;
}
private void downloadVideo() {
if(!videoTitle.isEmpty()) {
String videoSuffix = "." + MediaFormat.getSuffixById(videoStreams[selectedStream].format);
String audioSuffix = "." + MediaFormat.getSuffixById(audioStream.format);
Bundle args = new Bundle();
args.putString(DownloadDialog.FILE_SUFFIX_VIDEO, videoSuffix);
args.putString(DownloadDialog.FILE_SUFFIX_AUDIO, audioSuffix);
args.putString(DownloadDialog.TITLE, videoTitle);
args.putString(DownloadDialog.VIDEO_URL, videoStreams[selectedStream].url);
args.putString(DownloadDialog.AUDIO_URL, audioStream.url);
DownloadDialog downloadDialog = new DownloadDialog();
downloadDialog.setArguments(args);
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
}
}
private void openInBrowser() {
if(!videoTitle.isEmpty()) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(websiteUrl));
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.chooseBrowser)));
}
}
private void playWithKodi() {
if(!videoTitle.isEmpty()) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setPackage(KORE_PACKET);
intent.setData(Uri.parse(websiteUrl.replace("https", "http")));
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.koreNotFound)
.setPositiveButton(R.string.installeKore, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(activity.getString(R.string.fdroidKoreUrl)));
activity.startActivity(intent);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.create().show();
}
}
}
private void playAudio() {
Intent intent = new Intent();
try {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(audioStream.url),
MediaFormat.getMimeById(audioStream.format));
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
intent.putExtra("title", videoTitle);
activity.startActivity(intent); // HERE !!!
} catch (Exception e) {
e.printStackTrace();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.noPlayerFound)
.setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl)));
activity.startActivity(intent);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "You unlocked a secret unicorn.");
}
});
builder.create().show();
Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
e.printStackTrace();
}
}
}

View File

@@ -1,10 +1,10 @@
package org.schabi.newpipe.services;
package org.schabi.newpipe;
/**
* Created by Christian Schabesberger on 23.08.15.
/*
* Created by Christian Schabesberger on 24.12.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* StreamingService.java is part of NewPipe.
* ActivityCommunicator.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
@@ -20,16 +20,20 @@ package org.schabi.newpipe.services;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public interface StreamingService {
class ServiceInfo {
public String name = "";
}
ServiceInfo getServiceInfo();
VideoExtractor getExtractorInstance(String url);
SearchEngine getSearchEngineInstance();
/**
* Singleton:
* Used to send data between certain Activity/Services within the same process.
* This can be considered as an ugly hack inside the Android universe. **/
public class ActivityCommunicator {
/**When a VIEW_ACTION is caught this function will test if the url delivered within the calling
Intent was meant to be watched with this Service.
Return false if this service shall not allow to be callean through ACTIONs.*/
boolean acceptUrl(String videoUrl);
private static ActivityCommunicator activityCommunicator;
public static ActivityCommunicator getCommunicator() {
if(activityCommunicator == null) {
activityCommunicator = new ActivityCommunicator();
}
return activityCommunicator;
}
public volatile Class returnActivity;
}

View File

@@ -0,0 +1,220 @@
package org.schabi.newpipe;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.Log;
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import org.acra.ACRA;
import org.acra.config.ACRAConfiguration;
import org.acra.config.ACRAConfigurationException;
import org.acra.config.ConfigurationBuilder;
import org.acra.sender.ReportSenderFactory;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.report.AcraReportSenderFactory;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.StateSaver;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;
import io.reactivex.annotations.NonNull;
import io.reactivex.exceptions.CompositeException;
import io.reactivex.exceptions.MissingBackpressureException;
import io.reactivex.exceptions.OnErrorNotImplementedException;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.functions.Consumer;
import io.reactivex.plugins.RxJavaPlugins;
/*
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
* App.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 App extends Application {
protected static final String TAG = App.class.toString();
private RefWatcher refWatcher;
@SuppressWarnings("unchecked")
private static final Class<? extends ReportSenderFactory>[] reportSenderFactoryClasses = new Class[]{AcraReportSenderFactory.class};
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
initACRA();
}
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
refWatcher = installLeakCanary();
// Initialize settings first because others inits can use its values
SettingsActivity.initSettings(this);
NewPipe.init(getDownloader());
StateSaver.init(this);
initNotificationChannel();
// Initialize image loader
ImageLoader.getInstance().init(getImageLoaderConfigurations(10, 50));
configureRxJavaErrorHandler();
}
protected Downloader getDownloader() {
return org.schabi.newpipe.Downloader.init(null);
}
private void configureRxJavaErrorHandler() {
// https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " +
"throwable = [" + throwable.getClass().getName() + "]");
if (throwable instanceof UndeliverableException) {
// As UndeliverableException is a wrapper, get the cause of it to get the "real" exception
throwable = throwable.getCause();
}
final List<Throwable> errors;
if (throwable instanceof CompositeException) {
errors = ((CompositeException) throwable).getExceptions();
} else {
errors = Collections.singletonList(throwable);
}
for (final Throwable error : errors) {
if (isThrowableIgnored(error)) return;
if (isThrowableCritical(error)) {
reportException(error);
return;
}
}
// Out-of-lifecycle exceptions should only be reported if a debug user wishes so,
// When exception is not reported, log it
if (isDisposedRxExceptionsReported()) {
reportException(throwable);
} else {
Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", throwable);
}
}
private boolean isThrowableIgnored(@NonNull final Throwable throwable) {
// Don't crash the application over a simple network problem
return ExtractorHelper.hasAssignableCauseThrowable(throwable,
IOException.class, SocketException.class, // network api cancellation
InterruptedException.class, InterruptedIOException.class); // blocking code disposed
}
private boolean isThrowableCritical(@NonNull final Throwable throwable) {
// Though these exceptions cannot be ignored
return ExtractorHelper.hasAssignableCauseThrowable(throwable,
NullPointerException.class, IllegalArgumentException.class, // bug in app
OnErrorNotImplementedException.class, MissingBackpressureException.class,
IllegalStateException.class); // bug in operator
}
private void reportException(@NonNull final Throwable throwable) {
// Throw uncaught exception that will trigger the report system
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), throwable);
}
});
}
private ImageLoaderConfiguration getImageLoaderConfigurations(final int memoryCacheSizeMb,
final int diskCacheSizeMb) {
return new ImageLoaderConfiguration.Builder(this)
.memoryCache(new LRULimitedMemoryCache(memoryCacheSizeMb * 1024 * 1024))
.diskCacheSize(diskCacheSizeMb * 1024 * 1024)
.imageDownloader(new ImageDownloader(getApplicationContext()))
.build();
}
private void initACRA() {
try {
final ACRAConfiguration acraConfig = new ConfigurationBuilder(this)
.setReportSenderFactoryClasses(reportSenderFactoryClasses)
.setBuildConfigClass(BuildConfig.class)
.build();
ACRA.init(this, acraConfig);
} catch (ACRAConfigurationException ace) {
ace.printStackTrace();
ErrorActivity.reportError(this, ace, null, null, ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
"Could not initialize ACRA crash report", R.string.app_ui_crash));
}
}
public void initNotificationChannel() {
if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
return;
}
final String id = getString(R.string.notification_channel_id);
final CharSequence name = getString(R.string.notification_channel_name);
final String description = getString(R.string.notification_channel_description);
// Keep this below DEFAULT to avoid making noise on every notification update
final int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
mChannel.setDescription(description);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(mChannel);
}
@Nullable
public static RefWatcher getRefWatcher(Context context) {
final App application = (App) context.getApplicationContext();
return application.refWatcher;
}
protected RefWatcher installLeakCanary() {
return RefWatcher.DISABLED;
}
protected boolean isDisposedRxExceptionsReported() {
return false;
}
}

View File

@@ -0,0 +1,95 @@
package org.schabi.newpipe;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.leakcanary.RefWatcher;
import icepick.Icepick;
public abstract class BaseFragment extends Fragment {
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
protected boolean DEBUG = MainActivity.DEBUG;
protected AppCompatActivity activity;
public static final ImageLoader imageLoader = ImageLoader.getInstance();
/*//////////////////////////////////////////////////////////////////////////
// Fragment's Lifecycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
activity = (AppCompatActivity) context;
}
@Override
public void onDetach() {
super.onDetach();
activity = null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState);
if (savedInstanceState != null) onRestoreInstanceState(savedInstanceState);
}
@Override
public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
if (DEBUG) {
Log.d(TAG, "onViewCreated() called with: rootView = [" + rootView + "], savedInstanceState = [" + savedInstanceState + "]");
}
initViews(rootView, savedInstanceState);
initListeners();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
}
@Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = App.getRefWatcher(getActivity());
if (refWatcher != null) refWatcher.watch(this);
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
protected void initViews(View rootView, Bundle savedInstanceState) {
}
protected void initListeners() {
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
public void setTitle(String title) {
if (DEBUG) Log.d(TAG, "setTitle() called with: title = [" + title + "]");
if (activity != null && activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle(title);
}
}
}

View File

@@ -1,91 +0,0 @@
package org.schabi.newpipe;
import android.app.Dialog;
import android.app.DownloadManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import java.io.File;
/**
* Created by Christian Schabesberger on 21.09.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* DownloadDialog.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 DownloadDialog extends DialogFragment {
private static final String TAG = DialogFragment.class.getName();
public static final String TITLE = "name";
public static final String FILE_SUFFIX_AUDIO = "file_suffix_audio";
public static final String FILE_SUFFIX_VIDEO = "file_suffix_video";
public static final String AUDIO_URL = "audio_url";
public static final String VIDEO_URL = "video_url";
private Bundle arguments;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
arguments = getArguments();
super.onCreateDialog(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.downloadDialogTitle)
.setItems(R.array.downloadOptions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Context context = getActivity();
SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String suffix = "";
String title = arguments.getString(TITLE);
String url = "";
switch(which) {
case 0: // Video
suffix = arguments.getString(FILE_SUFFIX_VIDEO);
url = arguments.getString(VIDEO_URL);
break;
case 1:
suffix = arguments.getString(FILE_SUFFIX_AUDIO);
url = arguments.getString(AUDIO_URL);
break;
default:
Log.d(TAG, "lolz");
}
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(
Uri.parse(url));
request.setDestinationUri(Uri.fromFile(new File(
defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe")
+ "/" + title + suffix)));
try {
dm.enqueue(request);
} catch (Exception e) {
e.printStackTrace();
}
}
});
return builder.create();
}
}

View File

@@ -1,16 +1,27 @@
package org.schabi.newpipe;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import android.support.annotation.Nullable;
import android.text.TextUtils;
/**
* Created by Christian Schabesberger on 14.08.15.
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/*
* Created by Christian Schabesberger on 28.01.16.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* Downloader.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
@@ -27,70 +38,116 @@ import java.net.UnknownHostException;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class Downloader {
public class Downloader implements org.schabi.newpipe.extractor.Downloader {
public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
private static final String USER_AGENT = "Mozilla/5.0";
private static Downloader instance;
private String mCookies;
private OkHttpClient client;
/**Download the text file at the supplied URL as in download(String),
private Downloader(OkHttpClient.Builder builder) {
this.client = builder
.readTimeout(30, TimeUnit.SECONDS)
//.cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
.build();
}
/**
* It's recommended to call exactly once in the entire lifetime of the application.
*
* @param builder if null, default builder will be used
*/
public static Downloader init(@Nullable OkHttpClient.Builder builder) {
return instance = new Downloader(builder != null ? builder : new OkHttpClient.Builder());
}
public static Downloader getInstance() {
return instance;
}
public String getCookies() {
return mCookies;
}
public void setCookies(String cookies) {
mCookies = cookies;
}
/**
* Download the text file at the supplied URL as in download(String),
* but set the HTTP header field "Accept-Language" to the supplied string.
* @param siteUrl the URL of the text file to return the contents of
*
* @param siteUrl the URL of the text file to return the contents of
* @param language the language (usually a 2-character code) to set as the preferred language
* @return the contents of the specified text file*/
public static String download(String siteUrl, String language) {
String ret = "";
try {
URL url = new URL(siteUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Accept-Language", language);
ret = dl(con);
}
catch(Exception e) {
e.printStackTrace();
}
return ret;
}
/**Common functionality between download(String url) and download(String url, String language)*/
private static String dl(HttpURLConnection con) throws IOException {
StringBuilder response = new StringBuilder();
try {
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
while((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
}
catch(UnknownHostException uhe) {//thrown when there's no internet connection
uhe.printStackTrace();
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
}
return response.toString();
* @return the contents of the specified text file
*/
@Override
public String download(String siteUrl, String language) throws IOException, ReCaptchaException {
Map<String, String> requestProperties = new HashMap<>();
requestProperties.put("Accept-Language", language);
return download(siteUrl, requestProperties);
}
/**Download (via HTTP) the text file located at the supplied URL, and return its contents.
* Primarily intended for downloading web pages.
* @param siteUrl the URL of the text file to download
* @return the contents of the specified text file*/
public static String download(String siteUrl) {
String ret = "";
/**
* Download the text file at the supplied URL as in download(String),
* but set the HTTP headers included in the customProperties map.
*
* @param siteUrl the URL of the text file to return the contents of
* @param customProperties set request header properties
* @return the contents of the specified text file
* @throws IOException
*/
@Override
public String download(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
return getBody(siteUrl, customProperties).string();
}
public InputStream stream(String siteUrl) throws IOException {
try {
URL url = new URL(siteUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
ret = dl(con);
return getBody(siteUrl, Collections.emptyMap()).byteStream();
} catch (ReCaptchaException e) {
throw new IOException(e.getMessage(), e.getCause());
}
catch(Exception e) {
e.printStackTrace();
}
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);
for (Map.Entry<String, String> header : customProperties.entrySet()) {
requestBuilder.addHeader(header.getKey(), header.getValue());
}
return ret;
if (!TextUtils.isEmpty(mCookies)) {
requestBuilder.addHeader("Cookie", mCookies);
}
final Request request = requestBuilder.build();
final Response response = client.newCall(request).execute();
final ResponseBody body = response.body();
if (response.code() == 429) {
throw new ReCaptchaException("reCaptcha Challenge requested");
}
if (body == null) {
response.close();
return null;
}
return body;
}
/**
* Download (via HTTP) the text file located at the supplied URL, and return its contents.
* Primarily intended for downloading web pages.
*
* @param siteUrl the URL of the text file to download
* @return the contents of the specified text file
*/
@Override
public String download(String siteUrl) throws IOException, ReCaptchaException {
return download(siteUrl, Collections.emptyMap());
}
}

View File

@@ -0,0 +1,54 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
/*
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
* ExitActivity.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 ExitActivity extends Activity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 21) {
finishAndRemoveTask();
} else {
finish();
}
System.exit(0);
}
public static void exitAndRemoveFromRecentApps(Activity activity) {
Intent intent = new Intent(activity, ExitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.startActivity(intent);
}
}

View File

@@ -0,0 +1,46 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import org.schabi.newpipe.extractor.NewPipe;
import java.io.IOException;
import java.io.InputStream;
public class ImageDownloader extends BaseImageDownloader {
private final Resources resources;
private final SharedPreferences preferences;
private final String downloadThumbnailKey;
public ImageDownloader(Context context) {
super(context);
this.resources = context.getResources();
this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
this.downloadThumbnailKey = context.getString(R.string.download_thumbnail_key);
}
private boolean isDownloadingThumbnail() {
return preferences.getBoolean(downloadThumbnailKey, true);
}
@SuppressLint("ResourceType")
@Override
public InputStream getStream(String imageUri, Object extra) throws IOException {
if (isDownloadingThumbnail()) {
return super.getStream(imageUri, extra);
} else {
return resources.openRawResource(R.drawable.dummy_thumbnail_dark);
}
}
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
final Downloader downloader = (Downloader) NewPipe.getDownloader();
return downloader.stream(imageUri);
}
}

View File

@@ -0,0 +1,386 @@
/*
* Created by Christian Schabesberger on 02.08.16.
* <p>
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* DownloadActivity.java is part of NewPipe.
* <p>
* 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.
* <p>
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver;
import org.schabi.newpipe.util.ThemeHelper;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
private ActionBarDrawerToggle toggle = null;
private DrawerLayout drawer = null;
private NavigationView drawerItems = null;
private TextView headerServiceView = null;
/*//////////////////////////////////////////////////////////////////////////
// Activity's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getSupportFragmentManager() != null && getSupportFragmentManager().getBackStackEntryCount() == 0) {
initFragments();
}
setSupportActionBar(findViewById(R.id.toolbar));
setupDrawer();
}
private void setupDrawer() {
final Toolbar toolbar = findViewById(R.id.toolbar);
drawer = findViewById(R.id.drawer_layout);
drawerItems = findViewById(R.id.navigation);
for(StreamingService s : NewPipe.getServices()) {
String title =
s.getServiceInfo().getName() +
(ServiceHelper.isBeta(s) ? " (beta)" : "");
MenuItem item = drawerItems.getMenu()
.add(R.id.menu_services_group, s.getServiceId(), 0, title);
item.setIcon(ServiceHelper.getIcon(s.getServiceId()));
}
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
toggle.syncState();
drawer.addDrawerListener(toggle);
drawer.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
private int lastService;
@Override
public void onDrawerOpened(View drawerView) {
lastService = ServiceHelper.getSelectedServiceId(MainActivity.this);
}
@Override
public void onDrawerClosed(View drawerView) {
if (lastService != ServiceHelper.getSelectedServiceId(MainActivity.this)) {
new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
}
}
});
drawerItems.setNavigationItemSelectedListener(this::changeService);
setupDrawerFooter();
setupDrawerHeader();
}
private boolean changeService(MenuItem item) {
if (item.getGroupId() == R.id.menu_services_group) {
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(false);
ServiceHelper.setSelectedServiceId(this, item.getItemId());
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
} else {
return false;
}
drawer.closeDrawers();
return true;
}
private void setupDrawerFooter() {
ImageButton settings = findViewById(R.id.drawer_settings);
ImageButton downloads = findViewById(R.id.drawer_downloads);
ImageButton history = findViewById(R.id.drawer_history);
settings.setOnClickListener(view -> NavigationHelper.openSettings(this));
downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this));
history.setOnClickListener(view -> NavigationHelper.openHistory(this));
}
private void setupDrawerHeader() {
headerServiceView = findViewById(R.id.drawer_header_service_view);
Button action = findViewById(R.id.drawer_header_action_button);
action.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://newpipe.schabi.org/blog/"));
startActivity(intent);
drawer.closeDrawers();
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations()) {
StateSaver.clearStateFiles();
}
}
@Override
protected void onResume() {
super.onResume();
// close drawer on return, and don't show animation, so its looks like the drawer isn't open
// when the user returns to MainActivity
drawer.closeDrawer(Gravity.START, false);
try {
String selectedServiceName = NewPipe.getService(
ServiceHelper.getSelectedServiceId(this)).getServiceInfo().getName();
headerServiceView.setText(selectedServiceName);
} catch (Exception e) {
ErrorActivity.reportUiError(this, e);
}
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getBoolean(Constants.KEY_THEME_CHANGE, false)) {
if (DEBUG) Log.d(TAG, "Theme has changed, recreating activity...");
sharedPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, false).apply();
// https://stackoverflow.com/questions/10844112/runtimeexception-performing-pause-of-activity-that-is-not-resumed
// Briefly, let the activity resume properly posting the recreate call to end of the message queue
new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
}
if (sharedPreferences.getBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false)) {
if (DEBUG) Log.d(TAG, "main page has changed, recreating main fragment...");
sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false).apply();
NavigationHelper.openMainActivity(this);
}
}
@Override
protected void onNewIntent(Intent intent) {
if (DEBUG) Log.d(TAG, "onNewIntent() called with: intent = [" + intent + "]");
if (intent != null) {
// Return if launched from a launcher (e.g. Nova Launcher, Pixel Launcher ...)
// to not destroy the already created backstack
String action = intent.getAction();
if ((action != null && action.equals(Intent.ACTION_MAIN)) && intent.hasCategory(Intent.CATEGORY_LAUNCHER)) return;
}
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
@Override
public void onBackPressed() {
if (DEBUG) Log.d(TAG, "onBackPressed() called");
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
if (fragment instanceof BackPressable) {
if (((BackPressable) fragment).onBackPressed()) return;
}
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else super.onBackPressed();
}
/**
* Implement the following diagram behavior for the up button:
* <pre>
* +---------------+
* | Main Screen +----+
* +-------+-------+ |
* | |
* ▲ Up | Search Button
* | |
* +----+-----+ |
* +------------+ Search |◄-----+
* | +----+-----+
* | Open |
* | something ▲ Up
* | |
* | +------------+-------------+
* | | |
* | | Video <-> Channel |
* +---►| Channel <-> Playlist |
* | Video <-> .... |
* | |
* +--------------------------+
* </pre>
*/
private void onHomeButtonPressed() {
// If search fragment wasn't found in the backstack...
if (!NavigationHelper.tryGotoSearchFragment(getSupportFragmentManager())) {
// ...go to the main fragment
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "]");
super.onCreateOptionsMenu(menu);
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
if (!(fragment instanceof VideoDetailFragment)) {
findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner).setVisibility(View.GONE);
}
if (!(fragment instanceof SearchFragment)) {
findViewById(R.id.toolbar).findViewById(R.id.toolbar_search_container).setVisibility(View.GONE);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
}
updateDrawerNavigation();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (DEBUG) Log.d(TAG, "onOptionsItemSelected() called with: item = [" + item + "]");
int id = item.getItemId();
switch (id) {
case android.R.id.home:
onHomeButtonPressed();
return true;
case R.id.action_settings:
NavigationHelper.openSettings(this);
return true;
case R.id.action_show_downloads:
return NavigationHelper.openDownloads(this);
case R.id.action_about:
NavigationHelper.openAbout(this);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
private void initFragments() {
if (DEBUG) Log.d(TAG, "initFragments() called");
StateSaver.clearStateFiles();
if (getIntent() != null && getIntent().hasExtra(Constants.KEY_LINK_TYPE)) {
handleIntent(getIntent());
} else NavigationHelper.gotoMainFragment(getSupportFragmentManager());
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void updateDrawerNavigation() {
if (getSupportActionBar() == null) return;
final Toolbar toolbar = findViewById(R.id.toolbar);
final DrawerLayout drawer = findViewById(R.id.drawer_layout);
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
if (fragment instanceof MainFragment) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
if (toggle != null) {
toggle.syncState();
toolbar.setNavigationOnClickListener(v -> drawer.openDrawer(GravityCompat.START));
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);
}
} else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(v -> onHomeButtonPressed());
}
}
private void handleIntent(Intent intent) {
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
String url = intent.getStringExtra(Constants.KEY_URL);
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
String title = intent.getStringExtra(Constants.KEY_TITLE);
switch (((StreamingService.LinkType) intent.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
case STREAM:
boolean autoPlay = intent.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(), serviceId, url, title, autoPlay);
break;
case CHANNEL:
NavigationHelper.openChannelFragment(getSupportFragmentManager(), serviceId, url, title);
break;
case PLAYLIST:
NavigationHelper.openPlaylistFragment(getSupportFragmentManager(), serviceId, url, title);
break;
}
} else if (intent.hasExtra(Constants.KEY_OPEN_SEARCH)) {
String searchQuery = intent.getStringExtra(Constants.KEY_QUERY);
if (searchQuery == null) searchQuery = "";
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
NavigationHelper.openSearchFragment(getSupportFragmentManager(), serviceId, searchQuery);
} else {
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
}
}
}

View File

@@ -1,81 +0,0 @@
package org.schabi.newpipe;
/**
* Created by Adam Howard on 08/11/15.
*
* Copyright (c) Christian Schabesberger <chris.schabesberger@mailbox.org>
* and Adam Howard <achdisposable1@gmail.com> 2015
*
* VideoListAdapter.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/>.
*/
/**Static data about various media formats support by Newpipe, eg mime type, extension*/
public enum MediaFormat {
// id name suffix mime type
MPEG_4 (0x0, "MPEG-4", "mp4", "video/mp4"),
v3GPP (0x1, "3GPP", "3gp", "video/3gpp"),
WEBM (0x2, "WebM", "webm", "video/webm"),
M4A (0x3, "m4a", "m4a", "audio/mp4"),
WEBMA (0x4, "WebM", "webm", "audio/webm");
public final int id;
@SuppressWarnings("WeakerAccess")
public final String name;
@SuppressWarnings("WeakerAccess")
public final String suffix;
public final String mimeType;
MediaFormat(int id, String name, String suffix, String mimeType) {
this.id = id;
this.name = name;
this.suffix = suffix;
this.mimeType = mimeType;
}
/**Return the friendly name of the media format with the supplied id
* @param ident the id of the media format. Currently an arbitrary, NewPipe-specific number.
* @return the friendly name of the MediaFormat associated with this ids,
* or an empty String if none match it.*/
public static String getNameById(int ident) {
for (MediaFormat vf : MediaFormat.values()) {
if(vf.id == ident) return vf.name;
}
return "";
}
/**Return the file extension of the media format with the supplied id
* @param ident the id of the media format. Currently an arbitrary, NewPipe-specific number.
* @return the file extension of the MediaFormat associated with this ids,
* or an empty String if none match it.*/
public static String getSuffixById(int ident) {
for (MediaFormat vf : MediaFormat.values()) {
if(vf.id == ident) return vf.suffix;
}
return "";
}
/**Return the MIME type of the media format with the supplied id
* @param ident the id of the media format. Currently an arbitrary, NewPipe-specific number.
* @return the MIME type of the MediaFormat associated with this ids,
* or an empty String if none match it.*/
public static String getMimeById(int ident) {
for (MediaFormat vf : MediaFormat.values()) {
if(vf.id == ident) return vf.mimeType;
}
return "";
}
}

View File

@@ -0,0 +1,42 @@
package org.schabi.newpipe;
import android.arch.persistence.room.Room;
import android.content.Context;
import android.support.annotation.NonNull;
import org.schabi.newpipe.database.AppDatabase;
import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME;
import static org.schabi.newpipe.database.Migrations.MIGRATION_11_12;
public final class NewPipeDatabase {
private static volatile AppDatabase databaseInstance;
private NewPipeDatabase() {
//no instance
}
private static AppDatabase getDatabase(Context context) {
return Room
.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.addMigrations(MIGRATION_11_12)
.fallbackToDestructiveMigration()
.build();
}
@NonNull
public static AppDatabase getInstance(@NonNull Context context) {
AppDatabase result = databaseInstance;
if (result == null) {
synchronized (NewPipeDatabase.class) {
result = databaseInstance;
if (result == null) {
databaseInstance = (result = getDatabase(context));
}
}
}
return result;
}
}

View File

@@ -0,0 +1,49 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
/*
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
* PanicResponderActivity.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 PanicResponderActivity extends Activity {
public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER";
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
// TODO explicitly clear the search results once they are restored when the app restarts
// or if the app reloads the current video after being killed, that should be cleared also
ExitActivity.exitAndRemoveFromRecentApps(this);
}
if (Build.VERSION.SDK_INT >= 21) {
finishAndRemoveTask();
} else {
finish();
}
}
}

View File

@@ -0,0 +1,157 @@
package org.schabi.newpipe;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.webkit.CookieManager;
import android.webkit.ValueCallback;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/*
* Created by beneth <bmauduit@beneth.fr> on 06.12.16.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* ReCaptchaActivity.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 ReCaptchaActivity extends AppCompatActivity {
public static final int RECAPTCHA_REQUEST = 10;
public static final String TAG = ReCaptchaActivity.class.toString();
public static final String YT_URL = "https://www.youtube.com";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recaptcha);
// Set return to Cancel by default
setResult(RESULT_CANCELED);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.reCaptcha_title);
actionBar.setDisplayShowTitleEnabled(true);
}
WebView myWebView = findViewById(R.id.reCaptchaWebView);
// Enable Javascript
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
ReCaptchaWebViewClient webClient = new ReCaptchaWebViewClient(this);
myWebView.setWebViewClient(webClient);
// Cleaning cache, history and cookies from webView
myWebView.clearCache(true);
myWebView.clearHistory();
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean aBoolean) {}
});
} else {
cookieManager.removeAllCookie();
}
myWebView.loadUrl(YT_URL);
}
private class ReCaptchaWebViewClient extends WebViewClient {
private Activity context;
private String mCookies;
ReCaptchaWebViewClient(Activity ctx) {
context = ctx;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO: Start Loader
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
String cookies = CookieManager.getInstance().getCookie(url);
// TODO: Stop Loader
// find cookies : s_gl & goojf and Add cookies to Downloader
if (find_access_cookies(cookies)) {
// Give cookies to Downloader class
Downloader.getInstance().setCookies(mCookies);
// Closing activity and return to parent
setResult(RESULT_OK);
finish();
}
}
private boolean find_access_cookies(String cookies) {
boolean ret = false;
String c_s_gl = "";
String c_goojf = "";
String[] parts = cookies.split("; ");
for (String part : parts) {
if (part.trim().startsWith("s_gl")) {
c_s_gl = part.trim();
}
if (part.trim().startsWith("goojf")) {
c_goojf = part.trim();
}
}
if (c_s_gl.length() > 0 && c_goojf.length() > 0) {
ret = true;
//mCookies = c_s_gl + "; " + c_goojf;
// Youtube seems to also need the other cookies:
mCookies = cookies;
}
return ret;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home: {
Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
}
default:
return false;
}
}
}

View File

@@ -0,0 +1,574 @@
package org.schabi.newpipe;
import android.app.IntentService;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.StreamingService.LinkType;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.ChannelPlayQueue;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import icepick.Icepick;
import icepick.State;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
/**
* Get the url from the intent and open it in the chosen preferred player
*/
public class RouterActivity extends AppCompatActivity {
@State
protected int currentServiceId = -1;
private StreamingService currentService;
@State
protected LinkType currentLinkType;
@State
protected int selectedRadioPosition = -1;
protected int selectedPreviously = -1;
protected String currentUrl;
protected CompositeDisposable disposables = new CompositeDisposable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState);
if (TextUtils.isEmpty(currentUrl)) {
currentUrl = getUrl(getIntent());
if (TextUtils.isEmpty(currentUrl)) {
Toast.makeText(this, R.string.invalid_url_toast, Toast.LENGTH_LONG).show();
finish();
}
}
setTheme(ThemeHelper.isLightThemeSelected(this)
? R.style.RouterActivityThemeLight
: R.style.RouterActivityThemeDark);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
@Override
protected void onStart() {
super.onStart();
handleUrl(currentUrl);
}
@Override
protected void onDestroy() {
super.onDestroy();
disposables.clear();
}
private void handleUrl(String url) {
disposables.add(Observable
.fromCallable(() -> {
if (currentServiceId == -1) {
currentService = NewPipe.getServiceByUrl(url);
currentServiceId = currentService.getServiceId();
currentLinkType = currentService.getLinkTypeByUrl(url);
currentUrl = NavigationHelper.getCleanUrl(currentService, url, currentLinkType);
} else {
currentService = NewPipe.getService(currentServiceId);
}
return currentLinkType != LinkType.NONE;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result) {
onSuccess();
} else {
onError();
}
}, this::handleError));
}
private void handleError(Throwable error) {
error.printStackTrace();
if (error instanceof ExtractionException) {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
} else {
ExtractorHelper.handleGeneralException(this, -1, null, error, UserAction.SOMETHING_ELSE, null);
}
finish();
}
private void onError() {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
finish();
}
protected void onSuccess() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
if ((isExtAudioEnabled || isExtVideoEnabled) && currentLinkType != LinkType.STREAM) {
Toast.makeText(this, R.string.external_player_unsupported_link_type, Toast.LENGTH_LONG).show();
finish();
return;
}
// TODO: Add some sort of "capabilities" field to services (audio only, video and audio, etc.)
if (currentService == ServiceList.SoundCloud) {
handleChoice(getString(R.string.background_player_key));
return;
}
final String playerChoiceKey = preferences.getString(
getString(R.string.preferred_open_action_key),
getString(R.string.preferred_open_action_default));
final String alwaysAskKey = getString(R.string.always_ask_open_action_key);
if (playerChoiceKey.equals(alwaysAskKey)) {
showDialog();
} else {
handleChoice(playerChoiceKey);
}
}
private void showDialog() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(this,
ThemeHelper.isLightThemeSelected(this) ? R.style.LightTheme : R.style.DarkTheme);
LayoutInflater inflater = LayoutInflater.from(themeWrapper);
final LinearLayout rootLayout = (LinearLayout) inflater.inflate(R.layout.preferred_player_dialog_view, null, false);
final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
final AdapterChoiceItem[] choices = {
new AdapterChoiceItem(getString(R.string.show_info_key), getString(R.string.show_info),
resolveResourceIdFromAttr(themeWrapper, R.attr.info)),
new AdapterChoiceItem(getString(R.string.video_player_key), getString(R.string.video_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.play)),
new AdapterChoiceItem(getString(R.string.background_player_key), getString(R.string.background_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.audio)),
new AdapterChoiceItem(getString(R.string.popup_player_key), getString(R.string.popup_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.popup))
};
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
final int indexOfChild = radioGroup.indexOfChild(
radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
final AdapterChoiceItem choice = choices[indexOfChild];
handleChoice(choice.key);
if (which == DialogInterface.BUTTON_POSITIVE) {
preferences.edit().putString(getString(R.string.preferred_open_action_key), choice.key).apply();
}
};
final AlertDialog alertDialog = new AlertDialog.Builder(themeWrapper)
.setTitle(R.string.preferred_player_share_menu_title)
.setView(radioGroup)
.setCancelable(true)
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
.setPositiveButton(R.string.always, dialogButtonsClickListener)
.setOnDismissListener((dialog) -> finish())
.create();
alertDialog.setOnShowListener(dialog -> {
setDialogButtonsState(alertDialog, radioGroup.getCheckedRadioButtonId() != -1);
});
radioGroup.setOnCheckedChangeListener((group, checkedId) -> setDialogButtonsState(alertDialog, true));
final View.OnClickListener radioButtonsClickListener = v -> {
final int indexOfChild = radioGroup.indexOfChild(v);
if (indexOfChild == -1) return;
selectedPreviously = selectedRadioPosition;
selectedRadioPosition = indexOfChild;
if (selectedPreviously == selectedRadioPosition) {
handleChoice(choices[selectedRadioPosition].key);
}
};
int id = 12345;
for (AdapterChoiceItem item : choices) {
final RadioButton radioButton = (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
radioButton.setText(item.description);
radioButton.setCompoundDrawablesWithIntrinsicBounds(item.icon, 0, 0, 0);
radioButton.setChecked(false);
radioButton.setId(id++);
radioButton.setLayoutParams(new RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
radioButton.setOnClickListener(radioButtonsClickListener);
radioGroup.addView(radioButton);
}
if (selectedRadioPosition == -1) {
final String lastSelectedPlayer = preferences.getString(getString(R.string.preferred_open_action_last_selected_key), null);
if (!TextUtils.isEmpty(lastSelectedPlayer)) {
for (int i = 0; i < choices.length; i++) {
AdapterChoiceItem c = choices[i];
if (lastSelectedPlayer.equals(c.key)) {
selectedRadioPosition = i;
break;
}
}
}
}
selectedRadioPosition = Math.min(Math.max(-1, selectedRadioPosition), choices.length - 1);
if (selectedRadioPosition != -1) {
((RadioButton) radioGroup.getChildAt(selectedRadioPosition)).setChecked(true);
}
selectedPreviously = selectedRadioPosition;
alertDialog.show();
}
private void setDialogButtonsState(AlertDialog dialog, boolean state) {
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
if (negativeButton == null || positiveButton == null) return;
negativeButton.setEnabled(state);
positiveButton.setEnabled(state);
}
private void handleChoice(final String playerChoiceKey) {
if (Arrays.asList(getResources()
.getStringArray(R.array.preferred_open_action_values_list))
.contains(playerChoiceKey)) {
PreferenceManager.getDefaultSharedPreferences(this).edit()
.putString(getString(R.string.preferred_open_action_last_selected_key),
playerChoiceKey).apply();
}
if (playerChoiceKey.equals(getString(R.string.popup_player_key))
&& !PermissionHelper.isPopupEnabled(this)) {
PermissionHelper.showPopupEnablementToast(this);
finish();
return;
}
// stop and bypass FetcherService if InfoScreen was selected since
// StreamDetailFragment can fetch data itself
if(playerChoiceKey.equals(getString(R.string.show_info_key))) {
disposables.add(Observable
.fromCallable(() -> NavigationHelper.getIntentByLink(this, currentUrl))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(intent -> {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}, this::handleError)
);
return;
}
final Intent intent = new Intent(this, FetcherService.class);
intent.putExtra(FetcherService.KEY_CHOICE,
new Choice(currentService.getServiceId(),
currentLinkType,
currentUrl,
playerChoiceKey));
startService(intent);
finish();
}
private static class AdapterChoiceItem {
final String description, key;
@DrawableRes
final int icon;
AdapterChoiceItem(String key, String description, int icon) {
this.description = description;
this.key = key;
this.icon = icon;
}
}
private static class Choice implements Serializable {
final int serviceId;
final String url, playerChoice;
final LinkType linkType;
Choice(int serviceId, LinkType linkType, String url, String playerChoice) {
this.serviceId = serviceId;
this.linkType = linkType;
this.url = url;
this.playerChoice = playerChoice;
}
@Override
public String toString() {
return serviceId + ":" + url + " > " + linkType + " ::: " + playerChoice;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Service Fetcher
//////////////////////////////////////////////////////////////////////////*/
public static class FetcherService extends IntentService {
private static final int ID = 456;
public static final String KEY_CHOICE = "key_choice";
private Disposable fetcher;
public FetcherService() {
super(FetcherService.class.getSimpleName());
}
@Override
public void onCreate() {
super.onCreate();
startForeground(ID, createNotification().build());
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent == null) return;
final Serializable serializable = intent.getSerializableExtra(KEY_CHOICE);
if (!(serializable instanceof Choice)) return;
Choice playerChoice = (Choice) serializable;
handleChoice(playerChoice);
}
public void handleChoice(Choice choice) {
Single<? extends Info> single = null;
UserAction userAction = UserAction.SOMETHING_ELSE;
switch (choice.linkType) {
case STREAM:
single = ExtractorHelper.getStreamInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_STREAM;
break;
case CHANNEL:
single = ExtractorHelper.getChannelInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_CHANNEL;
break;
case PLAYLIST:
single = ExtractorHelper.getPlaylistInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_PLAYLIST;
break;
}
if (single != null) {
final UserAction finalUserAction = userAction;
final Consumer<Info> resultHandler = getResultHandler(choice);
fetcher = single
.observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> {
resultHandler.accept(info);
if (fetcher != null) fetcher.dispose();
}, throwable -> ExtractorHelper.handleGeneralException(this,
choice.serviceId, choice.url, throwable, finalUserAction, ", opened with " + choice.playerChoice));
}
}
public Consumer<Info> getResultHandler(Choice choice) {
return info -> {
final String videoPlayerKey = getString(R.string.video_player_key);
final String backgroundPlayerKey = getString(R.string.background_player_key);
final String popupPlayerKey = getString(R.string.popup_player_key);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
boolean useOldVideoPlayer = PlayerHelper.isUsingOldPlayer(this);
PlayQueue playQueue;
String playerChoice = choice.playerChoice;
if (info instanceof StreamInfo) {
if (playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
NavigationHelper.playOnExternalAudioPlayer(this, (StreamInfo) info);
} else if (playerChoice.equals(videoPlayerKey) && isExtVideoEnabled) {
NavigationHelper.playOnExternalVideoPlayer(this, (StreamInfo) info);
} else if (playerChoice.equals(videoPlayerKey) && useOldVideoPlayer) {
NavigationHelper.playOnOldVideoPlayer(this, (StreamInfo) info);
} else {
playQueue = new SinglePlayQueue((StreamInfo) info);
if (playerChoice.equals(videoPlayerKey)) {
NavigationHelper.playOnMainPlayer(this, playQueue);
} else if (playerChoice.equals(backgroundPlayerKey)) {
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
} else if (playerChoice.equals(popupPlayerKey)) {
NavigationHelper.enqueueOnPopupPlayer(this, playQueue, true);
}
}
}
if (info instanceof ChannelInfo || info instanceof PlaylistInfo) {
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
if (playerChoice.equals(videoPlayerKey)) {
NavigationHelper.playOnMainPlayer(this, playQueue);
} else if (playerChoice.equals(backgroundPlayerKey)) {
NavigationHelper.playOnBackgroundPlayer(this, playQueue);
} else if (playerChoice.equals(popupPlayerKey)) {
NavigationHelper.playOnPopupPlayer(this, playQueue);
}
}
};
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
if (fetcher != null) fetcher.dispose();
}
private NotificationCompat.Builder createNotification() {
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
.setOngoing(true)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentTitle(getString(R.string.preferred_player_fetcher_notification_title))
.setContentText(getString(R.string.preferred_player_fetcher_notification_message));
}
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
/**
* Removes invisible separators (\p{Z}) and punctuation characters including
* brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
* more details.
*/
private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
private String getUrl(Intent intent) {
// first gather data and find service
String videoUrl = null;
if (intent.getData() != null) {
// this means the video was called though another app
videoUrl = intent.getData().toString();
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
//this means that vidoe was called through share menu
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
final String[] uris = getUris(extraText);
videoUrl = uris.length > 0 ? uris[0] : null;
}
return videoUrl;
}
private String removeHeadingGibberish(final String input) {
int start = 0;
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
if (!input.substring(i, i + 1).matches("\\p{L}")) {
start = i + 1;
break;
}
}
return input.substring(start, input.length());
}
private String trim(final String input) {
if (input == null || input.length() < 1) {
return input;
} else {
String output = input;
while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
output = output.substring(1);
}
while (output.length() > 0
&& output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
output = output.substring(0, output.length() - 1);
}
return output;
}
}
/**
* Retrieves all Strings which look remotely like URLs from a text.
* Used if NewPipe was called through share menu.
*
* @param sharedText text to scan for URLs.
* @return potential URLs
*/
protected String[] getUris(final String sharedText) {
final Collection<String> result = new HashSet<>();
if (sharedText != null) {
final String[] array = sharedText.split("\\p{Space}");
for (String s : array) {
s = trim(s);
if (s.length() != 0) {
if (s.matches(".+://.+")) {
result.add(removeHeadingGibberish(s));
} else if (s.matches(".+\\..+")) {
result.add("http://" + s);
}
}
}
}
return result.toArray(new String[result.size()]);
}
}

View File

@@ -1,164 +0,0 @@
package org.schabi.newpipe;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Christian Schabesberger on 31.08.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* SettingsActivity.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 SettingsActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate = null;
@Override
protected void onCreate(Bundle savedInstanceBundle) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceBundle);
super.onCreate(savedInstanceBundle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
}
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings_screen);
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
private ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
@NonNull
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home) {
finish();
}
return true;
}
public static void initSettings(Context context) {
PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){
SharedPreferences.Editor spEditor = sp.edit();
String newPipeDownloadStorage =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe";
spEditor.putString(context.getString(R.string.downloadPathPreference)
, newPipeDownloadStorage);
spEditor.apply();
}
}
}

View File

@@ -1,101 +0,0 @@
package org.schabi.newpipe;
import org.schabi.newpipe.services.AbstractVideoInfo;
import java.util.List;
/**
* Created by Christian Schabesberger on 26.08.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoInfo.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/>.
*/
/**Info object for opened videos, ie the video ready to play.*/
@SuppressWarnings("ALL")
public class VideoInfo extends AbstractVideoInfo {
public String uploader_thumbnail_url = "";
public String description = "";
public VideoStream[] videoStreams = null;
public AudioStream[] audioStreams = null;
public int videoAvailableStatus = VIDEO_AVAILABLE;
public int duration = -1;
/*YouTube-specific fields
todo: move these to a subclass*/
public int age_limit = 0;
public int like_count = -1;
public int dislike_count = -1;
public String average_rating = "";
public VideoPreviewInfo nextVideo = null;
public List<VideoPreviewInfo> relatedVideos = null;
public int startPosition = -1;//in seconds. some metadata is not passed using a VideoInfo object!
public static final int VIDEO_AVAILABLE = 0x00;
public static final int VIDEO_UNAVAILABLE = 0x01;
public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;//German DRM organisation
public VideoInfo() {}
/**Creates a new VideoInfo object from an existing AbstractVideoInfo.
* All the shared properties are copied to the new VideoInfo.*/
@SuppressWarnings("WeakerAccess")
public VideoInfo(AbstractVideoInfo avi) {
this.id = avi.id;
this.title = avi.title;
this.uploader = avi.uploader;
this.thumbnail_url = avi.thumbnail_url;
this.thumbnail = avi.thumbnail;
this.webpage_url = avi.webpage_url;
this.upload_date = avi.upload_date;
this.upload_date = avi.upload_date;
this.view_count = avi.view_count;
//todo: better than this
if(avi instanceof VideoPreviewInfo) {//shitty String to convert code
String dur = ((VideoPreviewInfo)avi).duration;
int minutes = Integer.parseInt(dur.substring(0, dur.indexOf(":")));
int seconds = Integer.parseInt(dur.substring(dur.indexOf(":")+1, dur.length()));
this.duration = (minutes*60)+seconds;
}
}
public static class VideoStream {
public String url = ""; //url of the stream
public int format = -1;
public String resolution = "";
public VideoStream(String url, int format, String res) {
this.url = url; this.format = format; resolution = res;
}
}
@SuppressWarnings("unused")
public static class AudioStream {
public String url = "";
public int format = -1;
public int bandwidth = -1;
public int samplingRate = -1;
public AudioStream(String url, int format, int bandwidth, int samplingRate) {
this.url = url; this.format = format;
this.bandwidth = bandwidth; this.samplingRate = samplingRate;
}
}
}

View File

@@ -1,74 +0,0 @@
package org.schabi.newpipe;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Created by Christian Schabesberger on 24.10.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoInfoItemViewCreator.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/>.
*/
class VideoInfoItemViewCreator {
private final LayoutInflater inflater;
public VideoInfoItemViewCreator(LayoutInflater inflater) {
this.inflater = inflater;
}
public View getViewByVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info) {
ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.video_item, parent, false);
holder = new ViewHolder();
holder.itemThumbnailView = (ImageView) convertView.findViewById(R.id.itemThumbnailView);
holder.itemVideoTitleView = (TextView) convertView.findViewById(R.id.itemVideoTitleView);
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(info.thumbnail == null) {
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
} else {
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
}
holder.itemVideoTitleView.setText(info.title);
holder.itemUploaderView.setText(info.uploader);
holder.itemDurationView.setText(info.duration);
if(!info.upload_date.isEmpty()) {
holder.itemUploadDateView.setText(info.upload_date);
} else {
//tweak if necessary: This is a hack to prevent having white space in the layout :P
holder.itemUploadDateView.setText(String.format("%d", info.view_count));
}
return convertView;
}
private class ViewHolder {
public ImageView itemThumbnailView;
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView;
}
}

View File

@@ -1,150 +0,0 @@
package org.schabi.newpipe;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import org.schabi.newpipe.services.ServiceList;
import org.schabi.newpipe.services.StreamingService;
/**
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoItemDetailActivity.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 VideoItemDetailActivity extends AppCompatActivity {
private static final String TAG = VideoItemDetailActivity.class.toString();
private VideoItemDetailFragment fragment;
private String videoUrl;
private int currentStreamingService = -1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_videoitem_detail);
// Show the Up button in the action bar.
try {
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} catch(Exception e) {
Log.d(TAG, "Could not get SupportActionBar");
e.printStackTrace();
}
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
Bundle arguments = new Bundle();
if (savedInstanceState == null) {
// this means the video was called though another app
if (getIntent().getData() != null) {
videoUrl = getIntent().getData().toString();
StreamingService[] serviceList = ServiceList.getServices();
//VideoExtractor videoExtractor = null;
for (int i = 0; i < serviceList.length; i++) {
if (serviceList[i].acceptUrl(videoUrl)) {
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
currentStreamingService = i;
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
break;
}
}
if(currentStreamingService == -1) {
Toast.makeText(this, R.string.urlNotSupportedText, Toast.LENGTH_LONG)
.show();
}
//arguments.putString(VideoItemDetailFragment.VIDEO_URL,
// videoExtractor.getVideoUrl(videoExtractor.getVideoId(videoUrl)));//cleans URL
arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.autoPlayThroughIntent), false));
} else {
videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL);
currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1);
arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
}
} else {
videoUrl = savedInstanceState.getString(VideoItemDetailFragment.VIDEO_URL);
currentStreamingService = savedInstanceState.getInt(VideoItemDetailFragment.STREAMING_SERVICE);
arguments = savedInstanceState;
}
// Create the detail fragment and add it to the activity
// using a fragment transaction.
fragment = new VideoItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.videoitem_detail_container, fragment)
.commit();
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
outState.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
outState.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
Intent intent = new Intent(this, VideoItemListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
} else {
return fragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
fragment.onCreateOptionsMenu(menu, getMenuInflater());
return true;
}
}

View File

@@ -1,478 +0,0 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.view.MenuItem;
import java.net.URL;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Vector;
import org.schabi.newpipe.services.VideoExtractor;
import org.schabi.newpipe.services.ServiceList;
import org.schabi.newpipe.services.StreamingService;
/**
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoItemDetailFragment.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 VideoItemDetailFragment extends Fragment {
private static final String TAG = VideoItemDetailFragment.class.toString();
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
public static final String VIDEO_URL = "video_url";
public static final String STREAMING_SERVICE = "streaming_service";
public static final String AUTO_PLAY = "auto_play";
private AppCompatActivity activity;
private ActionBarHandler actionBarHandler;
private boolean autoPlayEnabled = false;
private VideoInfo currentVideoInfo = null;
private boolean showNextVideoItem = false;
private View thumbnailWindowLayout;
private FloatingActionButton playVideoButton;
private final Point initialThumbnailPos = new Point(0, 0);
public interface OnInvokeCreateOptionsMenuListener {
void createOptionsMenu();
}
private OnInvokeCreateOptionsMenuListener onInvokeCreateOptionsMenuListener = null;
private class VideoExtractorRunnable implements Runnable {
private final Handler h = new Handler();
private VideoExtractor videoExtractor;
private final StreamingService service;
private final String videoUrl;
public VideoExtractorRunnable(String videoUrl, StreamingService service) {
this.service = service;
this.videoUrl = videoUrl;
}
@Override
public void run() {
try {
this.videoExtractor = service.getExtractorInstance(videoUrl);
VideoInfo videoInfo = videoExtractor.getVideoInfo();
h.post(new VideoResultReturnedRunnable(videoInfo));
if (videoInfo.videoAvailableStatus == VideoInfo.VIDEO_AVAILABLE) {
h.post(new SetThumbnailRunnable(
BitmapFactory.decodeStream(
new URL(videoInfo.thumbnail_url)
.openConnection()
.getInputStream()),
SetThumbnailRunnable.VIDEO_THUMBNAIL));
h.post(new SetThumbnailRunnable(
BitmapFactory.decodeStream(
new URL(videoInfo.uploader_thumbnail_url)
.openConnection()
.getInputStream()),
SetThumbnailRunnable.CHANNEL_THUMBNAIL));
if(showNextVideoItem) {
h.post(new SetThumbnailRunnable(
BitmapFactory.decodeStream(
new URL(videoInfo.nextVideo.thumbnail_url)
.openConnection()
.getInputStream()),
SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class VideoResultReturnedRunnable implements Runnable {
private final VideoInfo videoInfo;
public VideoResultReturnedRunnable(VideoInfo videoInfo) {
this.videoInfo = videoInfo;
}
@Override
public void run() {
//todo: fix expired thread error:
// If the thread calling this runnable is expired, the following function will crash.
updateInfo(videoInfo);
}
}
private class SetThumbnailRunnable implements Runnable {
public static final int VIDEO_THUMBNAIL = 1;
public static final int CHANNEL_THUMBNAIL = 2;
public static final int NEXT_VIDEO_THUMBNAIL = 3;
private final Bitmap thumbnail;
private final int thumbnailId;
public SetThumbnailRunnable(Bitmap thumbnail, int id) {
this.thumbnail = thumbnail;
this.thumbnailId = id;
}
@Override
public void run() {
updateThumbnail(thumbnail, thumbnailId);
}
}
private void updateThumbnail(Bitmap thumbnail, int id) {
Activity a = getActivity();
ImageView thumbnailView;
try {
switch (id) {
case SetThumbnailRunnable.VIDEO_THUMBNAIL:
thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView);
break;
case SetThumbnailRunnable.CHANNEL_THUMBNAIL:
thumbnailView = (ImageView) a.findViewById(R.id.detailUploaderThumbnailView);
break;
case SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL:
FrameLayout nextVideoFrame = (FrameLayout) a.findViewById(R.id.detailNextVideoFrame);
thumbnailView = (ImageView) nextVideoFrame.findViewById(R.id.itemThumbnailView);
currentVideoInfo.nextVideo.thumbnail = thumbnail;
break;
default:
Log.d(TAG, "Error: Thumbnail id not known");
return;
}
if (thumbnailView != null) {
thumbnailView.setImageBitmap(thumbnail);
}
} catch (java.lang.NullPointerException e) {
// Not good program design, I know. :/
Log.w(TAG, "updateThumbnail(): Fragment closed before thread ended work");
}
}
private void updateInfo(VideoInfo info) {
currentVideoInfo = info;
Resources res = activity.getResources();
try {
VideoInfoItemViewCreator videoItemViewCreator =
new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()));
RelativeLayout textContentLayout = (RelativeLayout) activity.findViewById(R.id.detailTextContentLayout);
ProgressBar progressBar = (ProgressBar) activity.findViewById(R.id.detailProgressBar);
TextView videoTitleView = (TextView) activity.findViewById(R.id.detailVideoTitleView);
TextView uploaderView = (TextView) activity.findViewById(R.id.detailUploaderView);
TextView viewCountView = (TextView) activity.findViewById(R.id.detailViewCountView);
TextView thumbsUpView = (TextView) activity.findViewById(R.id.detailThumbsUpCountView);
TextView thumbsDownView = (TextView) activity.findViewById(R.id.detailThumbsDownCountView);
TextView uploadDateView = (TextView) activity.findViewById(R.id.detailUploadDateView);
TextView descriptionView = (TextView) activity.findViewById(R.id.detailDescriptionView);
ImageView thumbnailView = (ImageView) activity.findViewById(R.id.detailThumbnailView);
FrameLayout nextVideoFrame = (FrameLayout) activity.findViewById(R.id.detailNextVideoFrame);
RelativeLayout nextVideoRootFrame =
(RelativeLayout) activity.findViewById(R.id.detailNextVideoRootLayout);
View nextVideoView = videoItemViewCreator
.getViewByVideoInfoItem(null, nextVideoFrame, info.nextVideo);
nextVideoFrame.addView(nextVideoView);
Button nextVideoButton = (Button) activity.findViewById(R.id.detailNextVideoButton);
Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton);
textContentLayout.setVisibility(View.VISIBLE);
playVideoButton.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
if(!showNextVideoItem) {
nextVideoRootFrame.setVisibility(View.GONE);
similarVideosButton.setVisibility(View.GONE);
}
switch (info.videoAvailableStatus) {
case VideoInfo.VIDEO_AVAILABLE: {
videoTitleView.setText(info.title);
uploaderView.setText(info.uploader);
Locale locale = getPreferredLocale();
NumberFormat nf = NumberFormat.getInstance(locale);
String localisedViewCount = nf.format(info.view_count);
viewCountView.setText(
String.format(
res.getString(R.string.viewCountText), localisedViewCount));
thumbsUpView.setText(nf.format(info.like_count));
thumbsDownView.setText(nf.format(info.dislike_count));
@SuppressLint("SimpleDateFormat")
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date datum = null;
try {
datum = formatter.parse(info.upload_date);
} catch (ParseException e) {
e.printStackTrace();
}
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
String localisedDate = df.format(datum);
uploadDateView.setText(
String.format(res.getString(R.string.uploadDateText), localisedDate));
descriptionView.setText(Html.fromHtml(info.description));
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
actionBarHandler.setVideoInfo(info.webpage_url, info.title);
actionBarHandler.setStartPosition(info.startPosition);
// parse streams
Vector<VideoInfo.VideoStream> streamsToUse = new Vector<>();
for (VideoInfo.VideoStream i : info.videoStreams) {
if (useStream(i, streamsToUse)) {
streamsToUse.add(i);
}
}
VideoInfo.VideoStream[] streamList = new VideoInfo.VideoStream[streamsToUse.size()];
for (int i = 0; i < streamList.length; i++) {
streamList[i] = streamsToUse.get(i);
}
actionBarHandler.setStreams(streamList, info.audioStreams);
}
nextVideoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent detailIntent =
new Intent(getActivity(), VideoItemDetailActivity.class);
detailIntent.putExtra(
VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id);
detailIntent.putExtra(
VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url);
//todo: make id dynamic the following line is crap
detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, 0);
startActivity(detailIntent);
}
});
break;
case VideoInfo.VIDEO_UNAVAILABLE_GEMA:
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(
getResources(), R.drawable.gruese_die_gema_unangebracht));
break;
case VideoInfo.VIDEO_UNAVAILABLE:
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(
getResources(), R.drawable.not_available_monkey));
break;
default:
Log.e(TAG, "Video Available Status not known.");
}
if(autoPlayEnabled) {
actionBarHandler.playVideo();
}
} catch (java.lang.NullPointerException e) {
Log.w(TAG, "updateInfo(): Fragment closed before thread ended work... or else");
e.printStackTrace();
}
}
private boolean useStream(VideoInfo.VideoStream stream, Vector<VideoInfo.VideoStream> streams) {
for(VideoInfo.VideoStream i : streams) {
if(i.resolution.equals(stream.resolution)) {
return false;
}
}
return true;
}
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = (AppCompatActivity) getActivity();
showNextVideoItem = PreferenceManager.getDefaultSharedPreferences(getActivity())
.getBoolean(activity.getString(R.string.showNextVideo), true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_videoitem_detail, container, false);
actionBarHandler = new ActionBarHandler(activity);
actionBarHandler.setupNavMenu(activity);
if(onInvokeCreateOptionsMenuListener != null) {
onInvokeCreateOptionsMenuListener.createOptionsMenu();
}
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceBundle) {
super.onActivityCreated(savedInstanceBundle);
Activity a = getActivity();
playVideoButton = (FloatingActionButton) a.findViewById(R.id.playVideoButton);
thumbnailWindowLayout = a.findViewById(R.id.detailVideoThumbnailWindowLayout);
Button backgroundButton = (Button)
a.findViewById(R.id.detailVideoThumbnailWindowBackgroundButton);
// Sometimes when this fragment is not visible it still gets initiated
// then we must not try to access objects of this fragment.
// Otherwise the applications would crash.
if(playVideoButton != null) {
try {
StreamingService streamingService = ServiceList.getService(
getArguments().getInt(STREAMING_SERVICE));
Thread videoExtractorThread = new Thread(new VideoExtractorRunnable(
getArguments().getString(VIDEO_URL), streamingService));
autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY);
videoExtractorThread.start();
} catch (Exception e) {
e.printStackTrace();
}
playVideoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
actionBarHandler.playVideo();
}
});
backgroundButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
actionBarHandler.playVideo();
}
});
Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton);
similarVideosButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(activity, VideoItemListActivity.class);
//todo: find more elegant way to do this - converting from List to ArrayList sucks
ArrayList<VideoPreviewInfo> toParcel = new ArrayList<>(currentVideoInfo.relatedVideos);
//why oh why does the parcelable array put method have to be so damn specific
// about the class of its argument?
//why not a List<? extends Parcelable>?
intent.putParcelableArrayListExtra(VideoItemListActivity.VIDEO_INFO_ITEMS, toParcel);
activity.startActivity(intent);
}
});
// todo: Fix this workaround (probably with a better design), so that older android
// versions don't have problems rendering the thumbnail right.
if(Build.VERSION.SDK_INT >= 18) {
ImageView thumbnailView = (ImageView) activity.findViewById(R.id.detailThumbnailView);
thumbnailView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
// This is used to synchronize the thumbnailWindowButton and the playVideoButton
// inside the ScrollView with the actual size of the thumbnail.
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
RelativeLayout.LayoutParams newWindowLayoutParams =
(RelativeLayout.LayoutParams) thumbnailWindowLayout.getLayoutParams();
newWindowLayoutParams.height = bottom - top;
thumbnailWindowLayout.setLayoutParams(newWindowLayoutParams);
//noinspection SuspiciousNameCombination
initialThumbnailPos.set(top, left);
}
});
}
}
}
/**Returns the java.util.Locale object which corresponds to the locale set in NewPipe's preferences.
* Currently not affected by the device's locale.*/
private Locale getPreferredLocale() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
String languageKey = getContext().getString(R.string.searchLanguage);
//i know the following line defaults languageCode to "en", but java is picky about uninitialised values
// Schabi: well lint tels me the value is redundant. I'll suppress it for now.
@SuppressWarnings("UnusedAssignment")
String languageCode = "en";
languageCode = sp.getString(languageKey, "en");
if(languageCode.length() == 2) {
return new Locale(languageCode);
}
else if(languageCode.contains("_")) {
String country = languageCode
.substring(languageCode.indexOf("_"), languageCode.length());
return new Locale(languageCode.substring(0, 2), country);
}
return Locale.getDefault();
}
private boolean checkIfLandscape() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels < displayMetrics.widthPixels;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
actionBarHandler.setupMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return actionBarHandler.onItemSelected(item);
}
public void setOnInvokeCreateOptionsMenuListener(OnInvokeCreateOptionsMenuListener listener) {
this.onInvokeCreateOptionsMenuListener = listener;
}
}

View File

@@ -1,276 +0,0 @@
package org.schabi.newpipe;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import java.util.ArrayList;
import org.schabi.newpipe.services.ServiceList;
/**
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoItemListActivity.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 VideoItemListActivity extends AppCompatActivity
implements VideoItemListFragment.Callbacks {
private static final String TAG = VideoItemListFragment.class.toString();
// arguments to give to this activity
public static final String VIDEO_INFO_ITEMS = "video_info_items";
// savedInstanceBundle arguments
private static final String QUERY = "query";
private static final String STREAMING_SERVICE = "streaming_service";
// activity modes
private static final int SEARCH_MODE = 0;
private static final int PRESENT_VIDEOS_MODE = 1;
private int mode = SEARCH_MODE;
private int currentStreamingServiceId = -1;
private String searchQuery = "";
private VideoItemListFragment listFragment;
private VideoItemDetailFragment videoFragment = null;
private Menu menu = null;
private class SearchVideoQueryListener implements SearchView.OnQueryTextListener {
@Override
public boolean onQueryTextSubmit(String query) {
try {
searchQuery = query;
listFragment.search(query);
// hide virtual keyboard
InputMethodManager inputManager =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
try {
//noinspection ConstantConditions
inputManager.hideSoftInputFromWindow(
getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
} catch(NullPointerException e) {
Log.e(TAG, "Could not get widget with focus");
e.printStackTrace();
}
// clear focus
// 1. to not open up the keyboard after switching back to this
// 2. It's a workaround to a seeming bug by the Android OS it self, causing
// onQueryTextSubmit to trigger twice when focus is not cleared.
// See: http://stackoverflow.com/questions/17874951/searchview-onquerytextsubmit-runs-twice-while-i-pressed-once
getCurrentFocus().clearFocus();
} catch(Exception e) {
e.printStackTrace();
}
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return true;
}
}
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_videoitem_list);
//------ todo: remove this line when multiservice support is implemented ------
currentStreamingServiceId = ServiceList.getIdOfService("Youtube");
//-----------------------------------------------------------------------------
listFragment = (VideoItemListFragment) getSupportFragmentManager()
.findFragmentById(R.id.videoitem_list);
listFragment.setStreamingService(ServiceList.getService(currentStreamingServiceId));
Bundle arguments = getIntent().getExtras();
if(arguments != null) {
//Parcelable[] p = arguments.getParcelableArray(VIDEO_INFO_ITEMS);
ArrayList<VideoPreviewInfo> p = arguments.getParcelableArrayList(VIDEO_INFO_ITEMS);
if(p != null) {
mode = PRESENT_VIDEOS_MODE;
try {
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} catch (NullPointerException e) {
Log.e(TAG, "Could not get SupportActionBar");
e.printStackTrace();
}
listFragment.present(p);
}
}
if(savedInstanceState != null
&& mode != PRESENT_VIDEOS_MODE) {
searchQuery = savedInstanceState.getString(QUERY);
currentStreamingServiceId = savedInstanceState.getInt(STREAMING_SERVICE);
if(!searchQuery.isEmpty()) {
listFragment.search(searchQuery);
}
}
if (findViewById(R.id.videoitem_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((VideoItemListFragment) getSupportFragmentManager()
.findFragmentById(R.id.videoitem_list))
.setActivateOnItemClick(true);
SearchView searchView = (SearchView)findViewById(R.id.searchViewTablet);
if(mode != PRESENT_VIDEOS_MODE) {
// Somehow the seticonifiedbydefault property set by the layout xml is not working on
// the support version on SearchView, so it needs to be set programmatically.
searchView.setIconifiedByDefault(false);
searchView.setIconified(false);
searchView.setOnQueryTextListener(new SearchVideoQueryListener());
} else {
searchView.setVisibility(View.GONE);
}
}
SettingsActivity.initSettings(this);
}
/**
* Callback method from {@link VideoItemListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
@Override
public void onItemSelected(String id) {
VideoListAdapter listAdapter = (VideoListAdapter) ((VideoItemListFragment)
getSupportFragmentManager()
.findFragmentById(R.id.videoitem_list))
.getListAdapter();
String webpage_url = listAdapter.getVideoList().get((int) Long.parseLong(id)).webpage_url;
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(VideoItemDetailFragment.ARG_ITEM_ID, id);
arguments.putString(VideoItemDetailFragment.VIDEO_URL, webpage_url);
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingServiceId);
videoFragment = new VideoItemDetailFragment();
videoFragment.setArguments(arguments);
videoFragment.setOnInvokeCreateOptionsMenuListener(new VideoItemDetailFragment.OnInvokeCreateOptionsMenuListener() {
@Override
public void createOptionsMenu() {
menu.clear();
onCreateOptionsMenu(menu);
}
});
getSupportFragmentManager().beginTransaction()
.replace(R.id.videoitem_detail_container, videoFragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, VideoItemDetailActivity.class);
detailIntent.putExtra(VideoItemDetailFragment.ARG_ITEM_ID, id);
detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, webpage_url);
detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingServiceId);
startActivity(detailIntent);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.menu = menu;
MenuInflater inflater = getMenuInflater();
if(mode != PRESENT_VIDEOS_MODE &&
findViewById(R.id.videoitem_detail_container) == null) {
inflater.inflate(R.menu.videoitem_list, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setFocusable(false);
searchView.setOnQueryTextListener(
new SearchVideoQueryListener());
} else if (videoFragment != null){
videoFragment.onCreateOptionsMenu(menu, inflater);
} else {
inflater.inflate(R.menu.videoitem_two_pannel, menu);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case android.R.id.home: {
Intent intent = new Intent(this, VideoItemListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
}
case R.id.action_settings: {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
default:
return videoFragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/*
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
*/
outState.putString(QUERY, searchQuery);
outState.putInt(STREAMING_SERVICE, currentStreamingServiceId);
}
}

View File

@@ -1,360 +0,0 @@
package org.schabi.newpipe;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.Toast;
import java.net.URL;
import java.util.List;
import java.util.Vector;
import org.schabi.newpipe.services.SearchEngine;
import org.schabi.newpipe.services.StreamingService;
/**
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoItemListFragment.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 VideoItemListFragment extends ListFragment {
private static final String TAG = VideoItemListFragment.class.toString();
private StreamingService streamingService = null;
private VideoListAdapter videoListAdapter;
// activity modes
private static final int SEARCH_MODE = 0;
private static final int PRESENT_VIDEOS_MODE = 1;
private int mode = SEARCH_MODE;
private String query = "";
private int lastPage = 0;
private Thread searchThread = null;
private SearchRunnable searchRunnable = null;
private Thread loadThumbsThread = null;
private LoadThumbsRunnable loadThumbsRunnable = null;
// used to track down if results posted by threads ar still valid
private int currentRequestId = -1;
private ListView list;
private class ResultRunnable implements Runnable {
private final SearchEngine.Result result;
private final int requestId;
public ResultRunnable(SearchEngine.Result result, int requestId) {
this.result = result;
this.requestId = requestId;
}
@Override
public void run() {
updateListOnResult(result, requestId);
}
}
private class SearchRunnable implements Runnable {
private final SearchEngine engine;
private final String query;
private final int page;
final Handler h = new Handler();
private volatile boolean run = true;
private final int requestId;
public SearchRunnable(SearchEngine engine, String query, int page, int requestId) {
this.engine = engine;
this.query = query;
this.page = page;
this.requestId = requestId;
}
void terminate() {
run = false;
}
@Override
public void run() {
try {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
String searchLanguageKey = getContext().getString(R.string.searchLanguage);
String searchLanguage = sp.getString(searchLanguageKey, "en");
SearchEngine.Result result = engine.search(query, page, searchLanguage);
Log.i(TAG, "language code passed:\""+searchLanguage+"\"");
if(run) {
h.post(new ResultRunnable(result, requestId));
}
} catch(Exception e) {
e.printStackTrace();
h.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getActivity(), "Network Error", Toast.LENGTH_SHORT).show();
}
});
}
}
}
private class LoadThumbsRunnable implements Runnable {
private final Vector<String> thumbnailUrlList = new Vector<>();
private final Vector<Boolean> downloadedList;
final Handler h = new Handler();
private volatile boolean run = true;
private final int requestId;
public LoadThumbsRunnable(Vector<VideoPreviewInfo> videoList,
Vector<Boolean> downloadedList, int requestId) {
for(VideoPreviewInfo item : videoList) {
thumbnailUrlList.add(item.thumbnail_url);
}
this.downloadedList = downloadedList;
this.requestId = requestId;
}
public void terminate() {
run = false;
}
public boolean isRunning() {
return run;
}
@Override
public void run() {
for(int i = 0; i < thumbnailUrlList.size() && run; i++) {
if(!downloadedList.get(i)) {
Bitmap thumbnail;
try {
thumbnail = BitmapFactory.decodeStream(
new URL(thumbnailUrlList.get(i)).openConnection().getInputStream());
h.post(new SetThumbnailRunnable(i, thumbnail, requestId));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
private class SetThumbnailRunnable implements Runnable {
private final int index;
private final Bitmap thumbnail;
private final int requestId;
public SetThumbnailRunnable(int index, Bitmap thumbnail, int requestId) {
this.index = index;
this.thumbnail = thumbnail;
this.requestId = requestId;
}
@Override
public void run() {
if(requestId == currentRequestId) {
videoListAdapter.updateDownloadedThumbnailList(index);
videoListAdapter.setThumbnail(index, thumbnail);
}
}
}
public void present(List<VideoPreviewInfo> videoList) {
mode = PRESENT_VIDEOS_MODE;
setListShown(true);
getListView().smoothScrollToPosition(0);
updateList(videoList);
}
public void search(String query) {
mode = SEARCH_MODE;
this.query = query;
this.lastPage = 1;
videoListAdapter.clearVideoList();
setListShown(false);
startSearch(query, lastPage);
getListView().smoothScrollToPosition(0);
}
private void nextPage() {
lastPage++;
Log.d(TAG, getString(R.string.searchPage) + Integer.toString(lastPage));
startSearch(query, lastPage);
}
private void startSearch(String query, int page) {
currentRequestId++;
terminateThreads();
searchRunnable = new SearchRunnable(streamingService.getSearchEngineInstance(),
query, page, currentRequestId);
searchThread = new Thread(searchRunnable);
searchThread.start();
}
public void setStreamingService(StreamingService streamingService) {
this.streamingService = streamingService;
}
private void updateListOnResult(SearchEngine.Result result, int requestId) {
if(requestId == currentRequestId) {
setListShown(true);
if (result.resultList.isEmpty()) {
Toast.makeText(getActivity(), result.errorMessage, Toast.LENGTH_LONG).show();
} else {
if (!result.suggestion.isEmpty()) {
Toast.makeText(getActivity(), getString(R.string.didYouMean) + result.suggestion + " ?",
Toast.LENGTH_LONG).show();
}
updateList(result.resultList);
}
}
}
private void updateList(List<VideoPreviewInfo> list) {
try {
videoListAdapter.addVideoList(list);
terminateThreads();
loadThumbsRunnable = new LoadThumbsRunnable(videoListAdapter.getVideoList(),
videoListAdapter.getDownloadedThumbnailList(), currentRequestId);
loadThumbsThread = new Thread(loadThumbsRunnable);
loadThumbsThread.start();
} catch(java.lang.IllegalStateException e) {
Log.w(TAG, "Trying to set value while activity doesn't exist anymore.");
} catch(Exception e) {
e.printStackTrace();
}
}
private void terminateThreads() {
if(loadThumbsRunnable != null && loadThumbsRunnable.isRunning()) {
loadThumbsRunnable.terminate();
try {
loadThumbsThread.join();
} catch(Exception e) {
e.printStackTrace();
}
}
if(searchThread != null) {
searchRunnable.terminate();
// No need to join, since we don't really terminate the thread. We just demand
// it to post its result runnable into the gui main loop.
}
}
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
void onItemSelected(String id);
}
private Callbacks mCallbacks = null;
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
list = getListView();
videoListAdapter = new VideoListAdapter(getActivity(), this);
setListAdapter(videoListAdapter);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
long lastScrollDate = 0;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mode != PRESENT_VIDEOS_MODE
&& list.getChildAt(0) != null
&& list.getLastVisiblePosition() == list.getAdapter().getCount() - 1
&& list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) {
long time = System.currentTimeMillis();
if ((time - lastScrollDate) > 200) {
lastScrollDate = time;
nextPage();
}
}
}
});
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Activities containing this fragment must implement its callbacks.
if (!(context instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) context;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
setActivatedPosition(position);
mCallbacks.onItemSelected(Long.toString(id));
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(@SuppressWarnings("SameParameterValue") boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(activateOnItemClick
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}

View File

@@ -1,109 +0,0 @@
package org.schabi.newpipe;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.List;
import java.util.Vector;
/**
* Created by Christian Schabesberger on 11.08.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoListAdapter.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/>.
*/
class VideoListAdapter extends BaseAdapter {
private final Context context;
private final VideoInfoItemViewCreator viewCreator;
private Vector<VideoPreviewInfo> videoList = new Vector<>();
private Vector<Boolean> downloadedThumbnailList = new Vector<>();
private final ListView listView;
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(context));
this.listView = videoListFragment.getListView();
this.listView.setDivider(null);
this.listView.setDividerHeight(0);
this.context = context;
}
public void addVideoList(List<VideoPreviewInfo> videos) {
videoList.addAll(videos);
for(int i = 0; i < videos.size(); i++) {
downloadedThumbnailList.add(false);
}
notifyDataSetChanged();
}
public void clearVideoList() {
videoList = new Vector<>();
downloadedThumbnailList = new Vector<>();
notifyDataSetChanged();
}
public Vector<VideoPreviewInfo> getVideoList() {
return videoList;
}
public void updateDownloadedThumbnailList(int index) {
downloadedThumbnailList.set(index, true);
}
public Vector<Boolean> getDownloadedThumbnailList() {
return downloadedThumbnailList;
}
public void setThumbnail(int index, Bitmap thumbnail) {
videoList.get(index).thumbnail = thumbnail;
downloadedThumbnailList.set(index, true);
notifyDataSetChanged();
}
@Override
public int getCount() {
return videoList.size();
}
@Override
public Object getItem(int position) {
return videoList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = viewCreator.getViewByVideoInfoItem(convertView, parent, videoList.get(position));
if(listView.isItemChecked(position)) {
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube));
} else {
convertView.setBackgroundColor(0);
}
return convertView;
}
}

View File

@@ -1,79 +0,0 @@
package org.schabi.newpipe;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import org.schabi.newpipe.services.AbstractVideoInfo;
/**
* Created by Christian Schabesberger on 26.08.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoPreviewInfo.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/>.
*/
/**Info object for previews of unopened videos, eg search results, related videos*/
public class VideoPreviewInfo extends AbstractVideoInfo implements Parcelable {
public String duration = "";
@SuppressWarnings("WeakerAccess")
protected VideoPreviewInfo(Parcel in) {
id = in.readString();
title = in.readString();
uploader = in.readString();
duration = in.readString();
thumbnail_url = in.readString();
thumbnail = (Bitmap) in.readValue(Bitmap.class.getClassLoader());
webpage_url = in.readString();
upload_date = in.readString();
view_count = in.readLong();
}
public VideoPreviewInfo() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(title);
dest.writeString(uploader);
dest.writeString(duration);
dest.writeString(thumbnail_url);
dest.writeValue(thumbnail);
dest.writeString(webpage_url);
dest.writeString(upload_date);
dest.writeLong(view_count);
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<VideoPreviewInfo> CREATOR = new Parcelable.Creator<VideoPreviewInfo>() {
@Override
public VideoPreviewInfo createFromParcel(Parcel in) {
return new VideoPreviewInfo(in);
}
@Override
public VideoPreviewInfo[] newArray(int size) {
return new VideoPreviewInfo[size];
}
};
}

View File

@@ -0,0 +1,214 @@
package org.schabi.newpipe.about;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
public class AboutActivity extends AppCompatActivity {
/**
* List of all software components
*/
private static final SoftwareComponent[] SOFTWARE_COMPONENTS = new SoftwareComponent[]{
new SoftwareComponent("Giga Get", "2014", "Peter Cai", "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL2),
new SoftwareComponent("NewPipe Extractor", "2017", "Christian Schabesberger", "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3),
new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley", "https://github.com/jhy/jsoup", StandardLicenses.MIT),
new SoftwareComponent("Google Gson", "2008", "Google Inc", "https://github.com/google/gson", StandardLicenses.APACHE2),
new SoftwareComponent("Rhino", "2015", "Mozilla", "https://www.mozilla.org/rhino/", StandardLicenses.MPL2),
new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", "http://www.acra.ch", StandardLicenses.APACHE2),
new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich", "https://github.com/nostra13/Android-Universal-Image-Loader", StandardLicenses.APACHE2),
new SoftwareComponent("CircleImageView", "2014 - 2017", "Henning Dodenhof", "https://github.com/hdodenhof/CircleImageView", StandardLicenses.APACHE2),
new SoftwareComponent("ParalaxScrollView", "2014", "Nir Hartmann", "https://github.com/nirhart/ParallaxScroll", StandardLicenses.MIT),
new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam", "https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2),
new SoftwareComponent("ExoPlayer", "2014-2017", "Google Inc", "https://github.com/google/ExoPlayer", StandardLicenses.APACHE2),
new SoftwareComponent("RxAndroid", "2015", "The RxAndroid authors", "https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2),
new SoftwareComponent("RxJava", "2016-present", "RxJava Contributors", "https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2),
new SoftwareComponent("RxBinding", "2015", "Jake Wharton", "https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2)
};
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
setContentView(R.layout.activity_about);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_about, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
case R.id.action_settings:
NavigationHelper.openSettings(this);
return true;
case R.id.action_show_downloads:
return NavigationHelper.openDownloads(this);
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class AboutFragment extends Fragment {
public AboutFragment() {
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static AboutFragment newInstance() {
return new AboutFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_about, container, false);
TextView version = rootView.findViewById(R.id.app_version);
version.setText(BuildConfig.VERSION_NAME);
View githubLink = rootView.findViewById(R.id.github_link);
githubLink.setOnClickListener(new OnGithubLinkClickListener());
View donationLink = rootView.findViewById(R.id.donation_link);
donationLink.setOnClickListener(new OnDonationLinkClickListener());
View websiteLink = rootView.findViewById(R.id.website_link);
websiteLink.setOnClickListener(new OnWebsiteLinkClickListener());
return rootView;
}
private static class OnGithubLinkClickListener implements View.OnClickListener {
@Override
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.github_url)));
context.startActivity(intent);
}
}
private static class OnDonationLinkClickListener implements View.OnClickListener {
@Override
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.donation_url)));
context.startActivity(intent);
}
}
private static class OnWebsiteLinkClickListener implements View.OnClickListener {
@Override
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.website_url)));
context.startActivity(intent);
}
}
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return AboutFragment.newInstance();
case 1:
return LicenseFragment.newInstance(SOFTWARE_COMPONENTS);
}
return null;
}
@Override
public int getCount() {
// Show 2 total pages.
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.tab_about);
case 1:
return getString(R.string.tab_licenses);
}
return null;
}
}
}

View File

@@ -0,0 +1,73 @@
package org.schabi.newpipe.about;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A software license
*/
public class License implements Parcelable {
public static final Creator<License> CREATOR = new Creator<License>() {
@Override
public License createFromParcel(Parcel source) {
return new License(source);
}
@Override
public License[] newArray(int size) {
return new License[size];
}
};
private final String abbreviation;
private final String name;
private String filename;
public License(String name, String abbreviation, String filename) {
if(name == null) throw new NullPointerException("name is null");
if(abbreviation == null) throw new NullPointerException("abbreviation is null");
if(filename == null) throw new NullPointerException("filename is null");
this.name = name;
this.filename = filename;
this.abbreviation = abbreviation;
}
protected License(Parcel in) {
this.filename = in.readString();
this.abbreviation = in.readString();
this.name = in.readString();
}
public Uri getContentUri() {
return new Uri.Builder()
.scheme("file")
.path("/android_asset")
.appendPath(filename)
.build();
}
public String getAbbreviation() {
return abbreviation;
}
public String getFilename() {
return filename;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.filename);
dest.writeString(this.abbreviation);
dest.writeString(this.name);
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,132 @@
package org.schabi.newpipe.about;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.*;
import android.widget.TextView;
import org.schabi.newpipe.R;
import java.util.Arrays;
import java.util.Comparator;
/**
* Fragment containing the software licenses
*/
public class LicenseFragment extends Fragment {
private static final String ARG_COMPONENTS = "components";
private SoftwareComponent[] softwareComponents;
private SoftwareComponent mComponentForContextMenu;
public static LicenseFragment newInstance(SoftwareComponent[] softwareComponents) {
if(softwareComponents == null) {
throw new NullPointerException("softwareComponents is null");
}
LicenseFragment fragment = new LicenseFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents);
fragment.setArguments(bundle);
return fragment;
}
/**
* Shows a popup containing the license
* @param context the context to use
* @param license the license to show
*/
public static void showLicense(Context context, License license) {
new LicenseFragmentHelper().execute(context, license);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
softwareComponents = (SoftwareComponent[]) getArguments().getParcelableArray(ARG_COMPONENTS);
// Sort components by name
Arrays.sort(softwareComponents, new Comparator<SoftwareComponent>() {
@Override
public int compare(SoftwareComponent o1, SoftwareComponent o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_licenses, container, false);
ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
View licenseLink = rootView.findViewById(R.id.app_read_license);
licenseLink.setOnClickListener(new OnReadFullLicenseClickListener());
for (final SoftwareComponent component : softwareComponents) {
View componentView = inflater.inflate(R.layout.item_software_component, container, false);
TextView softwareName = componentView.findViewById(R.id.name);
TextView copyright = componentView.findViewById(R.id.copyright);
softwareName.setText(component.getName());
copyright.setText(getContext().getString(R.string.copyright,
component.getYears(),
component.getCopyrightOwner(),
component.getLicense().getAbbreviation()));
componentView.setTag(component);
componentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
if (context != null) {
showLicense(context, component.getLicense());
}
}
});
softwareComponentsView.addView(componentView);
registerForContextMenu(componentView);
}
return rootView;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getActivity().getMenuInflater();
SoftwareComponent component = (SoftwareComponent) v.getTag();
menu.setHeaderTitle(component.getName());
inflater.inflate(R.menu.software_component, menu);
super.onCreateContextMenu(menu, v, menuInfo);
mComponentForContextMenu = (SoftwareComponent) v.getTag();
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// item.getMenuInfo() is null so we use the tag of the view
final SoftwareComponent component = mComponentForContextMenu;
if (component == null) {
return false;
}
switch (item.getItemId()) {
case R.id.action_website:
openWebsite(component.getLink());
return true;
case R.id.action_show_license:
showLicense(getContext(), component.getLicense());
}
return false;
}
private void openWebsite(String componentLink) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(componentLink));
startActivity(browserIntent);
}
private static class OnReadFullLicenseClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
LicenseFragment.showLicense(v.getContext(), StandardLicenses.GPL3);
}
}
}

View File

@@ -0,0 +1,111 @@
package org.schabi.newpipe.about;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
private Context context;
private License license;
@Override
protected Integer doInBackground(Object... objects) {
context = (Context) objects[0];
license = (License) objects[1];
return 1;
}
@Override
protected void onPostExecute(Integer result){
String webViewData = getFormattedLicense(context, license);
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle(license.getName());
WebView wv = new WebView(context);
wv.loadData(webViewData, "text/html; charset=UTF-8", null);
alert.setView(wv);
alert.setNegativeButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.show();
}
/**
* @param context the context to use
* @param license the license
* @return String which contains a HTML formatted license page styled according to the context's theme
*/
public static String getFormattedLicense(Context context, License license) {
if(context == null) {
throw new NullPointerException("context is null");
}
if(license == null) {
throw new NullPointerException("license is null");
}
String licenseContent = "";
String webViewData;
try {
BufferedReader in = new BufferedReader(new InputStreamReader(context.getAssets().open(license.getFilename()), "UTF-8"));
String str;
while ((str = in.readLine()) != null) {
licenseContent += str;
}
in.close();
// split the HTML file and insert the stylesheet into the HEAD of the file
String[] insert = licenseContent.split("</head>");
webViewData = insert[0] + "<style type=\"text/css\">"
+ getLicenseStylesheet(context) + "</style></head>"
+ insert[1];
} catch (Exception e) {
throw new NullPointerException("could not get license file:" + getLicenseStylesheet(context));
}
return webViewData;
}
/**
*
* @param context
* @return String which is a CSS stylesheet according to the context's theme
*/
public static String getLicenseStylesheet(Context context) {
boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
return "body{padding:12px 15px;margin:0;background:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_license_background_color
: R.color.dark_license_background_color)
+ ";color:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_license_text_color
: R.color.dark_license_text_color) + ";}"
+ "a[href]{color:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_youtube_primary_color
: R.color.dark_youtube_primary_color) + ";}"
+ "pre{white-space: pre-wrap;}";
}
/**
* Cast R.color to a hexadecimal color value
* @param context the context to use
* @param color the color number from R.color
* @return a six characters long String with hexadecimal RGB values
*/
public static String getHexRGBColor(Context context, int color) {
return context.getResources().getString(color).substring(3);
}
}

View File

@@ -0,0 +1,83 @@
package org.schabi.newpipe.about;
import android.os.Parcel;
import android.os.Parcelable;
public class SoftwareComponent implements Parcelable {
public static final Creator<SoftwareComponent> CREATOR = new Creator<SoftwareComponent>() {
@Override
public SoftwareComponent createFromParcel(Parcel source) {
return new SoftwareComponent(source);
}
@Override
public SoftwareComponent[] newArray(int size) {
return new SoftwareComponent[size];
}
};
public String getName() {
return name;
}
public String getYears() {
return years;
}
public String getCopyrightOwner() {
return copyrightOwner;
}
public String getLink() {
return link;
}
public String getVersion() {
return version;
}
private final License license;
private final String name;
private final String years;
private final String copyrightOwner;
private final String link;
private final String version;
public SoftwareComponent(String name, String years, String copyrightOwner, String link, License license) {
this.name = name;
this.years = years;
this.copyrightOwner = copyrightOwner;
this.link = link;
this.license = license;
this.version = null;
}
protected SoftwareComponent(Parcel in) {
this.name = in.readString();
this.license = in.readParcelable(License.class.getClassLoader());
this.copyrightOwner = in.readString();
this.link = in.readString();
this.years = in.readString();
this.version = in.readString();
}
public License getLicense() {
return license;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeParcelable(license, flags);
dest.writeString(copyrightOwner);
dest.writeString(link);
dest.writeString(years);
dest.writeString(version);
}
}

View File

@@ -0,0 +1,12 @@
package org.schabi.newpipe.about;
/**
* Standard software licenses
*/
public final class StandardLicenses {
public static final License GPL2 = new License("GNU General Public License, Version 2.0", "GPLv2", "gpl_2.html");
public static final License GPL3 = new License("GNU General Public License, Version 3.0", "GPLv3", "gpl_3.html");
public static final License APACHE2 = new License("Apache License, Version 2.0", "ALv2", "apache2.html");
public static final License MPL2 = new License("Mozilla Public License, Version 2.0", "MPL 2.0", "mpl2.html");
public static final License MIT = new License("MIT License", "MIT", "mit.html");
}

View File

@@ -0,0 +1,55 @@
package org.schabi.newpipe.database;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;
import android.arch.persistence.room.TypeConverters;
import org.schabi.newpipe.database.history.dao.SearchHistoryDAO;
import org.schabi.newpipe.database.history.dao.StreamHistoryDAO;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
import org.schabi.newpipe.database.playlist.dao.PlaylistDAO;
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
import org.schabi.newpipe.database.playlist.dao.PlaylistStreamDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.dao.StreamDAO;
import org.schabi.newpipe.database.stream.dao.StreamStateDAO;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.database.subscription.SubscriptionDAO;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import static org.schabi.newpipe.database.Migrations.DB_VER_12_0;
@TypeConverters({Converters.class})
@Database(
entities = {
SubscriptionEntity.class, SearchHistoryEntry.class,
StreamEntity.class, StreamHistoryEntity.class, StreamStateEntity.class,
PlaylistEntity.class, PlaylistStreamEntity.class, PlaylistRemoteEntity.class
},
version = DB_VER_12_0,
exportSchema = false
)
public abstract class AppDatabase extends RoomDatabase {
public static final String DATABASE_NAME = "newpipe.db";
public abstract SubscriptionDAO subscriptionDAO();
public abstract SearchHistoryDAO searchHistoryDAO();
public abstract StreamDAO streamDAO();
public abstract StreamHistoryDAO streamHistoryDAO();
public abstract StreamStateDAO streamStateDAO();
public abstract PlaylistDAO playlistDAO();
public abstract PlaylistStreamDAO playlistStreamDAO();
public abstract PlaylistRemoteDAO playlistRemoteDAO();
}

View File

@@ -0,0 +1,46 @@
package org.schabi.newpipe.database;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Update;
import java.util.Collection;
import java.util.List;
import io.reactivex.Flowable;
@Dao
public interface BasicDAO<Entity> {
/* Inserts */
@Insert(onConflict = OnConflictStrategy.FAIL)
long insert(final Entity entity);
@Insert(onConflict = OnConflictStrategy.FAIL)
List<Long> insertAll(final Entity... entities);
@Insert(onConflict = OnConflictStrategy.FAIL)
List<Long> insertAll(final Collection<Entity> entities);
/* Searches */
Flowable<List<Entity>> getAll();
Flowable<List<Entity>> listByService(int serviceId);
/* Deletes */
@Delete
int delete(final Entity entity);
@Delete
int delete(final Collection<Entity> entities);
int deleteAll();
/* Updates */
@Update
int update(final Entity entity);
@Update
int update(final Collection<Entity> entities);
}

View File

@@ -0,0 +1,40 @@
package org.schabi.newpipe.database;
import android.arch.persistence.room.TypeConverter;
import org.schabi.newpipe.extractor.stream.StreamType;
import java.util.Date;
public class Converters {
/**
* Convert a long value to a date
* @param value the long value
* @return the date
*/
@TypeConverter
public static Date fromTimestamp(Long value) {
return value == null ? null : new Date(value);
}
/**
* Convert a date to a long value
* @param date the date
* @return the long value
*/
@TypeConverter
public static Long dateToTimestamp(Date date) {
return date == null ? null : date.getTime();
}
@TypeConverter
public static StreamType streamTypeOf(String value) {
return StreamType.valueOf(value);
}
@TypeConverter
public static String stringOf(StreamType streamType) {
return streamType.name();
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.database;
public interface LocalItem {
enum LocalItemType {
PLAYLIST_LOCAL_ITEM,
PLAYLIST_REMOTE_ITEM,
PLAYLIST_STREAM_ITEM,
STATISTIC_STREAM_ITEM,
}
LocalItemType getLocalItemType();
}

View File

@@ -0,0 +1,61 @@
package org.schabi.newpipe.database;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.migration.Migration;
import android.support.annotation.NonNull;
public class Migrations {
public static final int DB_VER_11_0 = 1;
public static final int DB_VER_12_0 = 2;
public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
/*
* Unfortunately these queries must be hardcoded due to the possibility of
* schema and names changing at a later date, thus invalidating the older migration
* scripts if they are not hardcoded.
* */
// Not much we can do about this, since room doesn't create tables before migration.
// It's either this or blasting the entire database anew.
database.execSQL("CREATE INDEX `index_search_history_search` ON `search_history` (`search`)");
database.execSQL("CREATE TABLE IF NOT EXISTS `streams` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `service_id` INTEGER NOT NULL, `url` TEXT, `title` TEXT, `stream_type` TEXT, `duration` INTEGER, `uploader` TEXT, `thumbnail_url` TEXT)");
database.execSQL("CREATE UNIQUE INDEX `index_streams_service_id_url` ON `streams` (`service_id`, `url`)");
database.execSQL("CREATE TABLE IF NOT EXISTS `stream_history` (`stream_id` INTEGER NOT NULL, `access_date` INTEGER NOT NULL, `repeat_count` INTEGER NOT NULL, PRIMARY KEY(`stream_id`, `access_date`), FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE )");
database.execSQL("CREATE INDEX `index_stream_history_stream_id` ON `stream_history` (`stream_id`)");
database.execSQL("CREATE TABLE IF NOT EXISTS `stream_state` (`stream_id` INTEGER NOT NULL, `progress_time` INTEGER NOT NULL, PRIMARY KEY(`stream_id`), FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE )");
database.execSQL("CREATE TABLE IF NOT EXISTS `playlists` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `thumbnail_url` TEXT)");
database.execSQL("CREATE INDEX `index_playlists_name` ON `playlists` (`name`)");
database.execSQL("CREATE TABLE IF NOT EXISTS `playlist_stream_join` (`playlist_id` INTEGER NOT NULL, `stream_id` INTEGER NOT NULL, `join_index` INTEGER NOT NULL, PRIMARY KEY(`playlist_id`, `join_index`), FOREIGN KEY(`playlist_id`) REFERENCES `playlists`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
database.execSQL("CREATE UNIQUE INDEX `index_playlist_stream_join_playlist_id_join_index` ON `playlist_stream_join` (`playlist_id`, `join_index`)");
database.execSQL("CREATE INDEX `index_playlist_stream_join_stream_id` ON `playlist_stream_join` (`stream_id`)");
database.execSQL("CREATE TABLE IF NOT EXISTS `remote_playlists` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, `thumbnail_url` TEXT, `uploader` TEXT, `stream_count` INTEGER)");
database.execSQL("CREATE INDEX `index_remote_playlists_name` ON `remote_playlists` (`name`)");
database.execSQL("CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` ON `remote_playlists` (`service_id`, `url`)");
// Populate streams table with existing entries in watch history
// Latest data first, thus ignoring older entries with the same indices
database.execSQL("INSERT OR IGNORE INTO streams (service_id, url, title, " +
"stream_type, duration, uploader, thumbnail_url) " +
"SELECT service_id, url, title, 'VIDEO_STREAM', duration, " +
"uploader, thumbnail_url " +
"FROM watch_history " +
"ORDER BY creation_date DESC");
// Once the streams have PKs, join them with the normalized history table
// and populate it with the remaining data from watch history
database.execSQL("INSERT INTO stream_history (stream_id, access_date, repeat_count)" +
"SELECT uid, creation_date, 1 " +
"FROM watch_history INNER JOIN streams " +
"ON watch_history.service_id == streams.service_id " +
"AND watch_history.url == streams.url " +
"ORDER BY creation_date DESC");
database.execSQL("DROP TABLE IF EXISTS watch_history");
}
};
}

View File

@@ -0,0 +1,7 @@
package org.schabi.newpipe.database.history.dao;
import org.schabi.newpipe.database.BasicDAO;
public interface HistoryDAO<T> extends BasicDAO<T> {
T getLatestEntry();
}

View File

@@ -0,0 +1,50 @@
package org.schabi.newpipe.database.history.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.support.annotation.Nullable;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.CREATION_DATE;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.ID;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SERVICE_ID;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.TABLE_NAME;
@Dao
public interface SearchHistoryDAO extends HistoryDAO<SearchHistoryEntry> {
String ORDER_BY_CREATION_DATE = " ORDER BY " + CREATION_DATE + " DESC";
@Query("SELECT * FROM " + TABLE_NAME +
" WHERE " + ID + " = (SELECT MAX(" + ID + ") FROM " + TABLE_NAME + ")")
@Nullable
SearchHistoryEntry getLatestEntry();
@Query("DELETE FROM " + TABLE_NAME)
@Override
int deleteAll();
@Query("DELETE FROM " + TABLE_NAME + " WHERE " + SEARCH + " = :query")
int deleteAllWhereQuery(String query);
@Query("SELECT * FROM " + TABLE_NAME + ORDER_BY_CREATION_DATE)
@Override
Flowable<List<SearchHistoryEntry>> getAll();
@Query("SELECT * FROM " + TABLE_NAME + " GROUP BY " + SEARCH + ORDER_BY_CREATION_DATE + " LIMIT :limit")
Flowable<List<SearchHistoryEntry>> getUniqueEntries(int limit);
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + SERVICE_ID + " = :serviceId" + ORDER_BY_CREATION_DATE)
@Override
Flowable<List<SearchHistoryEntry>> listByService(int serviceId);
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + SEARCH + " LIKE :query || '%' GROUP BY " + SEARCH + " LIMIT :limit")
Flowable<List<SearchHistoryEntry>> getSimilarEntries(String query, int limit);
}

View File

@@ -0,0 +1,68 @@
package org.schabi.newpipe.database.history.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.support.annotation.Nullable;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_REPEAT_COUNT;
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_LATEST_DATE;
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_WATCH_COUNT;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
@Dao
public abstract class StreamHistoryDAO implements HistoryDAO<StreamHistoryEntity> {
@Query("SELECT * FROM " + STREAM_HISTORY_TABLE +
" WHERE " + STREAM_ACCESS_DATE + " = " +
"(SELECT MAX(" + STREAM_ACCESS_DATE + ") FROM " + STREAM_HISTORY_TABLE + ")")
@Override
@Nullable
public abstract StreamHistoryEntity getLatestEntry();
@Override
@Query("SELECT * FROM " + STREAM_HISTORY_TABLE)
public abstract Flowable<List<StreamHistoryEntity>> getAll();
@Override
@Query("DELETE FROM " + STREAM_HISTORY_TABLE)
public abstract int deleteAll();
@Override
public Flowable<List<StreamHistoryEntity>> listByService(int serviceId) {
throw new UnsupportedOperationException();
}
@Query("SELECT * FROM " + STREAM_TABLE +
" INNER JOIN " + STREAM_HISTORY_TABLE +
" ON " + STREAM_ID + " = " + JOIN_STREAM_ID +
" ORDER BY " + STREAM_ACCESS_DATE + " DESC")
public abstract Flowable<List<StreamHistoryEntry>> getHistory();
@Query("DELETE FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
public abstract int deleteStreamHistory(final long streamId);
@Query("SELECT * FROM " + STREAM_TABLE +
// Select the latest entry and watch count for each stream id on history table
" INNER JOIN " +
"(SELECT " + JOIN_STREAM_ID + ", " +
" MAX(" + STREAM_ACCESS_DATE + ") AS " + STREAM_LATEST_DATE + ", " +
" SUM(" + STREAM_REPEAT_COUNT + ") AS " + STREAM_WATCH_COUNT +
" FROM " + STREAM_HISTORY_TABLE + " GROUP BY " + JOIN_STREAM_ID + ")" +
" ON " + STREAM_ID + " = " + JOIN_STREAM_ID)
public abstract Flowable<List<StreamStatisticsEntry>> getStatistics();
}

View File

@@ -0,0 +1,79 @@
package org.schabi.newpipe.database.history.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import java.util.Date;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
@Entity(tableName = SearchHistoryEntry.TABLE_NAME,
indices = {@Index(value = SEARCH)})
public class SearchHistoryEntry {
public static final String ID = "id";
public static final String TABLE_NAME = "search_history";
public static final String SERVICE_ID = "service_id";
public static final String CREATION_DATE = "creation_date";
public static final String SEARCH = "search";
@ColumnInfo(name = ID)
@PrimaryKey(autoGenerate = true)
private long id;
@ColumnInfo(name = CREATION_DATE)
private Date creationDate;
@ColumnInfo(name = SERVICE_ID)
private int serviceId;
@ColumnInfo(name = SEARCH)
private String search;
public SearchHistoryEntry(Date creationDate, int serviceId, String search) {
this.serviceId = serviceId;
this.creationDate = creationDate;
this.search = search;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public int getServiceId() {
return serviceId;
}
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
public String getSearch() {
return search;
}
public void setSearch(String search) {
this.search = search;
}
@Ignore
public boolean hasEqualValues(SearchHistoryEntry otherEntry) {
return getServiceId() == otherEntry.getServiceId() &&
getSearch().equals(otherEntry.getSearch());
}
}

View File

@@ -0,0 +1,79 @@
package org.schabi.newpipe.database.history.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.support.annotation.NonNull;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import java.util.Date;
import static android.arch.persistence.room.ForeignKey.CASCADE;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
@Entity(tableName = STREAM_HISTORY_TABLE,
primaryKeys = {JOIN_STREAM_ID, STREAM_ACCESS_DATE},
// No need to index for timestamp as they will almost always be unique
indices = {@Index(value = {JOIN_STREAM_ID})},
foreignKeys = {
@ForeignKey(entity = StreamEntity.class,
parentColumns = StreamEntity.STREAM_ID,
childColumns = JOIN_STREAM_ID,
onDelete = CASCADE, onUpdate = CASCADE)
})
public class StreamHistoryEntity {
final public static String STREAM_HISTORY_TABLE = "stream_history";
final public static String JOIN_STREAM_ID = "stream_id";
final public static String STREAM_ACCESS_DATE = "access_date";
final public static String STREAM_REPEAT_COUNT = "repeat_count";
@ColumnInfo(name = JOIN_STREAM_ID)
private long streamUid;
@NonNull
@ColumnInfo(name = STREAM_ACCESS_DATE)
private Date accessDate;
@ColumnInfo(name = STREAM_REPEAT_COUNT)
private long repeatCount;
public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long repeatCount) {
this.streamUid = streamUid;
this.accessDate = accessDate;
this.repeatCount = repeatCount;
}
@Ignore
public StreamHistoryEntity(long streamUid, @NonNull Date accessDate) {
this(streamUid, accessDate, 1);
}
public long getStreamUid() {
return streamUid;
}
public void setStreamUid(long streamUid) {
this.streamUid = streamUid;
}
public Date getAccessDate() {
return accessDate;
}
public void setAccessDate(@NonNull Date accessDate) {
this.accessDate = accessDate;
}
public long getRepeatCount() {
return repeatCount;
}
public void setRepeatCount(long repeatCount) {
this.repeatCount = repeatCount;
}
}

View File

@@ -0,0 +1,59 @@
package org.schabi.newpipe.database.history.model;
import android.arch.persistence.room.ColumnInfo;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamType;
import java.util.Date;
public class StreamHistoryEntry {
@ColumnInfo(name = StreamEntity.STREAM_ID)
final public long uid;
@ColumnInfo(name = StreamEntity.STREAM_SERVICE_ID)
final public int serviceId;
@ColumnInfo(name = StreamEntity.STREAM_URL)
final public String url;
@ColumnInfo(name = StreamEntity.STREAM_TITLE)
final public String title;
@ColumnInfo(name = StreamEntity.STREAM_TYPE)
final public StreamType streamType;
@ColumnInfo(name = StreamEntity.STREAM_DURATION)
final public long duration;
@ColumnInfo(name = StreamEntity.STREAM_UPLOADER)
final public String uploader;
@ColumnInfo(name = StreamEntity.STREAM_THUMBNAIL_URL)
final public String thumbnailUrl;
@ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID)
final public long streamId;
@ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE)
final public Date accessDate;
@ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT)
final public long repeatCount;
public StreamHistoryEntry(long uid, int serviceId, String url, String title,
StreamType streamType, long duration, String uploader,
String thumbnailUrl, long streamId, Date accessDate,
long repeatCount) {
this.uid = uid;
this.serviceId = serviceId;
this.url = url;
this.title = title;
this.streamType = streamType;
this.duration = duration;
this.uploader = uploader;
this.thumbnailUrl = thumbnailUrl;
this.streamId = streamId;
this.accessDate = accessDate;
this.repeatCount = repeatCount;
}
public StreamHistoryEntity toStreamHistoryEntity() {
return new StreamHistoryEntity(streamId, accessDate, repeatCount);
}
public boolean hasEqualValues(StreamHistoryEntry other) {
return this.uid == other.uid && streamId == other.streamId &&
accessDate.compareTo(other.accessDate) == 0;
}
}

View File

@@ -0,0 +1,7 @@
package org.schabi.newpipe.database.playlist;
import org.schabi.newpipe.database.LocalItem;
public interface PlaylistLocalItem extends LocalItem {
String getOrderingName();
}

View File

@@ -0,0 +1,37 @@
package org.schabi.newpipe.database.playlist;
import android.arch.persistence.room.ColumnInfo;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_URL;
public class PlaylistMetadataEntry implements PlaylistLocalItem {
final public static String PLAYLIST_STREAM_COUNT = "streamCount";
@ColumnInfo(name = PLAYLIST_ID)
final public long uid;
@ColumnInfo(name = PLAYLIST_NAME)
final public String name;
@ColumnInfo(name = PLAYLIST_THUMBNAIL_URL)
final public String thumbnailUrl;
@ColumnInfo(name = PLAYLIST_STREAM_COUNT)
final public long streamCount;
public PlaylistMetadataEntry(long uid, String name, String thumbnailUrl, long streamCount) {
this.uid = uid;
this.name = name;
this.thumbnailUrl = thumbnailUrl;
this.streamCount = streamCount;
}
@Override
public LocalItemType getLocalItemType() {
return LocalItemType.PLAYLIST_LOCAL_ITEM;
}
@Override
public String getOrderingName() {
return name;
}
}

View File

@@ -0,0 +1,60 @@
package org.schabi.newpipe.database.playlist;
import android.arch.persistence.room.ColumnInfo;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
public class PlaylistStreamEntry implements LocalItem {
@ColumnInfo(name = StreamEntity.STREAM_ID)
final public long uid;
@ColumnInfo(name = StreamEntity.STREAM_SERVICE_ID)
final public int serviceId;
@ColumnInfo(name = StreamEntity.STREAM_URL)
final public String url;
@ColumnInfo(name = StreamEntity.STREAM_TITLE)
final public String title;
@ColumnInfo(name = StreamEntity.STREAM_TYPE)
final public StreamType streamType;
@ColumnInfo(name = StreamEntity.STREAM_DURATION)
final public long duration;
@ColumnInfo(name = StreamEntity.STREAM_UPLOADER)
final public String uploader;
@ColumnInfo(name = StreamEntity.STREAM_THUMBNAIL_URL)
final public String thumbnailUrl;
@ColumnInfo(name = PlaylistStreamEntity.JOIN_STREAM_ID)
final public long streamId;
@ColumnInfo(name = PlaylistStreamEntity.JOIN_INDEX)
final public int joinIndex;
public PlaylistStreamEntry(long uid, int serviceId, String url, String title,
StreamType streamType, long duration, String uploader,
String thumbnailUrl, long streamId, int joinIndex) {
this.uid = uid;
this.serviceId = serviceId;
this.url = url;
this.title = title;
this.streamType = streamType;
this.duration = duration;
this.uploader = uploader;
this.thumbnailUrl = thumbnailUrl;
this.streamId = streamId;
this.joinIndex = joinIndex;
}
public StreamInfoItem toStreamInfoItem() throws IllegalArgumentException {
StreamInfoItem item = new StreamInfoItem(serviceId, url, title, streamType);
item.setThumbnailUrl(thumbnailUrl);
item.setUploaderName(uploader);
item.setDuration(duration);
return item;
}
@Override
public LocalItemType getLocalItemType() {
return LocalItemType.PLAYLIST_STREAM_ITEM;
}
}

View File

@@ -0,0 +1,38 @@
package org.schabi.newpipe.database.playlist.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
@Dao
public abstract class PlaylistDAO implements BasicDAO<PlaylistEntity> {
@Override
@Query("SELECT * FROM " + PLAYLIST_TABLE)
public abstract Flowable<List<PlaylistEntity>> getAll();
@Override
@Query("DELETE FROM " + PLAYLIST_TABLE)
public abstract int deleteAll();
@Override
public Flowable<List<PlaylistEntity>> listByService(int serviceId) {
throw new UnsupportedOperationException();
}
@Query("SELECT * FROM " + PLAYLIST_TABLE + " WHERE " + PLAYLIST_ID + " = :playlistId")
public abstract Flowable<List<PlaylistEntity>> getPlaylist(final long playlistId);
@Query("DELETE FROM " + PLAYLIST_TABLE + " WHERE " + PLAYLIST_ID + " = :playlistId")
public abstract int deletePlaylist(final long playlistId);
}

View File

@@ -0,0 +1,60 @@
package org.schabi.newpipe.database.playlist.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
@Dao
public abstract class PlaylistRemoteDAO implements BasicDAO<PlaylistRemoteEntity> {
@Override
@Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE)
public abstract Flowable<List<PlaylistRemoteEntity>> getAll();
@Override
@Query("DELETE FROM " + REMOTE_PLAYLIST_TABLE)
public abstract int deleteAll();
@Override
@Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE +
" WHERE " + REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<PlaylistRemoteEntity>> listByService(int serviceId);
@Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE + " WHERE " +
REMOTE_PLAYLIST_URL + " = :url AND " +
REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<PlaylistRemoteEntity>> getPlaylist(long serviceId, String url);
@Query("SELECT " + REMOTE_PLAYLIST_ID + " FROM " + REMOTE_PLAYLIST_TABLE +
" WHERE " +
REMOTE_PLAYLIST_URL + " = :url AND " + REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
abstract Long getPlaylistIdInternal(long serviceId, String url);
@Transaction
public long upsert(PlaylistRemoteEntity playlist) {
final Long playlistId = getPlaylistIdInternal(playlist.getServiceId(), playlist.getUrl());
if (playlistId == null) {
return insert(playlist);
} else {
playlist.setUid(playlistId);
update(playlist);
return playlistId;
}
}
@Query("DELETE FROM " + REMOTE_PLAYLIST_TABLE +
" WHERE " + REMOTE_PLAYLIST_ID + " = :playlistId")
public abstract int deletePlaylist(final long playlistId);
}

View File

@@ -0,0 +1,69 @@
package org.schabi.newpipe.database.playlist.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.*;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.*;
import static org.schabi.newpipe.database.stream.model.StreamEntity.*;
@Dao
public abstract class PlaylistStreamDAO implements BasicDAO<PlaylistStreamEntity> {
@Override
@Query("SELECT * FROM " + PLAYLIST_STREAM_JOIN_TABLE)
public abstract Flowable<List<PlaylistStreamEntity>> getAll();
@Override
@Query("DELETE FROM " + PLAYLIST_STREAM_JOIN_TABLE)
public abstract int deleteAll();
@Override
public Flowable<List<PlaylistStreamEntity>> listByService(int serviceId) {
throw new UnsupportedOperationException();
}
@Query("DELETE FROM " + PLAYLIST_STREAM_JOIN_TABLE +
" WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
public abstract void deleteBatch(final long playlistId);
@Query("SELECT COALESCE(MAX(" + JOIN_INDEX + "), -1)" +
" FROM " + PLAYLIST_STREAM_JOIN_TABLE +
" WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
public abstract Flowable<Integer> getMaximumIndexOf(final long playlistId);
@Transaction
@Query("SELECT * FROM " + STREAM_TABLE + " INNER JOIN " +
// get ids of streams of the given playlist
"(SELECT " + JOIN_STREAM_ID + "," + JOIN_INDEX +
" FROM " + PLAYLIST_STREAM_JOIN_TABLE +
" WHERE " + JOIN_PLAYLIST_ID + " = :playlistId)" +
// then merge with the stream metadata
" ON " + STREAM_ID + " = " + JOIN_STREAM_ID +
" ORDER BY " + JOIN_INDEX + " ASC")
public abstract Flowable<List<PlaylistStreamEntry>> getOrderedStreamsOf(long playlistId);
@Transaction
@Query("SELECT " + PLAYLIST_ID + ", " + PLAYLIST_NAME + ", " +
PLAYLIST_THUMBNAIL_URL + ", " +
"COALESCE(COUNT(" + JOIN_PLAYLIST_ID + "), 0) AS " + PLAYLIST_STREAM_COUNT +
" FROM " + PLAYLIST_TABLE +
" LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE +
" ON " + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID +
" GROUP BY " + JOIN_PLAYLIST_ID +
" ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
public abstract Flowable<List<PlaylistMetadataEntry>> getPlaylistMetadata();
}

View File

@@ -0,0 +1,59 @@
package org.schabi.newpipe.database.playlist.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import java.util.Date;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
@Entity(tableName = PLAYLIST_TABLE,
indices = {@Index(value = {PLAYLIST_NAME})})
public class PlaylistEntity {
final public static String PLAYLIST_TABLE = "playlists";
final public static String PLAYLIST_ID = "uid";
final public static String PLAYLIST_NAME = "name";
final public static String PLAYLIST_THUMBNAIL_URL = "thumbnail_url";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = PLAYLIST_ID)
private long uid = 0;
@ColumnInfo(name = PLAYLIST_NAME)
private String name;
@ColumnInfo(name = PLAYLIST_THUMBNAIL_URL)
private String thumbnailUrl;
public PlaylistEntity(String name, String thumbnailUrl) {
this.name = name;
this.thumbnailUrl = thumbnailUrl;
}
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
}

View File

@@ -0,0 +1,139 @@
package org.schabi.newpipe.database.playlist.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.util.Constants;
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
@Entity(tableName = REMOTE_PLAYLIST_TABLE,
indices = {
@Index(value = {REMOTE_PLAYLIST_NAME}),
@Index(value = {REMOTE_PLAYLIST_SERVICE_ID, REMOTE_PLAYLIST_URL}, unique = true)
})
public class PlaylistRemoteEntity implements PlaylistLocalItem {
final public static String REMOTE_PLAYLIST_TABLE = "remote_playlists";
final public static String REMOTE_PLAYLIST_ID = "uid";
final public static String REMOTE_PLAYLIST_SERVICE_ID = "service_id";
final public static String REMOTE_PLAYLIST_NAME = "name";
final public static String REMOTE_PLAYLIST_URL = "url";
final public static String REMOTE_PLAYLIST_THUMBNAIL_URL = "thumbnail_url";
final public static String REMOTE_PLAYLIST_UPLOADER_NAME = "uploader";
final public static String REMOTE_PLAYLIST_STREAM_COUNT = "stream_count";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = REMOTE_PLAYLIST_ID)
private long uid = 0;
@ColumnInfo(name = REMOTE_PLAYLIST_SERVICE_ID)
private int serviceId = Constants.NO_SERVICE_ID;
@ColumnInfo(name = REMOTE_PLAYLIST_NAME)
private String name;
@ColumnInfo(name = REMOTE_PLAYLIST_URL)
private String url;
@ColumnInfo(name = REMOTE_PLAYLIST_THUMBNAIL_URL)
private String thumbnailUrl;
@ColumnInfo(name = REMOTE_PLAYLIST_UPLOADER_NAME)
private String uploader;
@ColumnInfo(name = REMOTE_PLAYLIST_STREAM_COUNT)
private Long streamCount;
public PlaylistRemoteEntity(int serviceId, String name, String url, String thumbnailUrl,
String uploader, Long streamCount) {
this.serviceId = serviceId;
this.name = name;
this.url = url;
this.thumbnailUrl = thumbnailUrl;
this.uploader = uploader;
this.streamCount = streamCount;
}
@Ignore
public PlaylistRemoteEntity(final PlaylistInfo info) {
this(info.getServiceId(), info.getName(), info.getUrl(),
info.getThumbnailUrl() == null ? info.getUploaderAvatarUrl() : info.getThumbnailUrl(),
info.getUploaderName(), info.getStreamCount());
}
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public int getServiceId() {
return serviceId;
}
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUploader() {
return uploader;
}
public void setUploader(String uploader) {
this.uploader = uploader;
}
public Long getStreamCount() {
return streamCount;
}
public void setStreamCount(Long streamCount) {
this.streamCount = streamCount;
}
@Override
public LocalItemType getLocalItemType() {
return PLAYLIST_REMOTE_ITEM;
}
@Override
public String getOrderingName() {
return name;
}
}

View File

@@ -0,0 +1,77 @@
package org.schabi.newpipe.database.playlist.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
import android.arch.persistence.room.Index;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import static android.arch.persistence.room.ForeignKey.CASCADE;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_INDEX;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
@Entity(tableName = PLAYLIST_STREAM_JOIN_TABLE,
primaryKeys = {JOIN_PLAYLIST_ID, JOIN_INDEX},
indices = {
@Index(value = {JOIN_PLAYLIST_ID, JOIN_INDEX}, unique = true),
@Index(value = {JOIN_STREAM_ID})
},
foreignKeys = {
@ForeignKey(entity = PlaylistEntity.class,
parentColumns = PlaylistEntity.PLAYLIST_ID,
childColumns = JOIN_PLAYLIST_ID,
onDelete = CASCADE, onUpdate = CASCADE, deferred = true),
@ForeignKey(entity = StreamEntity.class,
parentColumns = StreamEntity.STREAM_ID,
childColumns = JOIN_STREAM_ID,
onDelete = CASCADE, onUpdate = CASCADE, deferred = true)
})
public class PlaylistStreamEntity {
final public static String PLAYLIST_STREAM_JOIN_TABLE = "playlist_stream_join";
final public static String JOIN_PLAYLIST_ID = "playlist_id";
final public static String JOIN_STREAM_ID = "stream_id";
final public static String JOIN_INDEX = "join_index";
@ColumnInfo(name = JOIN_PLAYLIST_ID)
private long playlistUid;
@ColumnInfo(name = JOIN_STREAM_ID)
private long streamUid;
@ColumnInfo(name = JOIN_INDEX)
private int index;
public PlaylistStreamEntity(final long playlistUid, final long streamUid, final int index) {
this.playlistUid = playlistUid;
this.streamUid = streamUid;
this.index = index;
}
public long getPlaylistUid() {
return playlistUid;
}
public long getStreamUid() {
return streamUid;
}
public int getIndex() {
return index;
}
public void setPlaylistUid(long playlistUid) {
this.playlistUid = playlistUid;
}
public void setStreamUid(long streamUid) {
this.streamUid = streamUid;
}
public void setIndex(int index) {
this.index = index;
}
}

View File

@@ -0,0 +1,69 @@
package org.schabi.newpipe.database.stream;
import android.arch.persistence.room.ColumnInfo;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import java.util.Date;
public class StreamStatisticsEntry implements LocalItem {
final public static String STREAM_LATEST_DATE = "latestAccess";
final public static String STREAM_WATCH_COUNT = "watchCount";
@ColumnInfo(name = StreamEntity.STREAM_ID)
final public long uid;
@ColumnInfo(name = StreamEntity.STREAM_SERVICE_ID)
final public int serviceId;
@ColumnInfo(name = StreamEntity.STREAM_URL)
final public String url;
@ColumnInfo(name = StreamEntity.STREAM_TITLE)
final public String title;
@ColumnInfo(name = StreamEntity.STREAM_TYPE)
final public StreamType streamType;
@ColumnInfo(name = StreamEntity.STREAM_DURATION)
final public long duration;
@ColumnInfo(name = StreamEntity.STREAM_UPLOADER)
final public String uploader;
@ColumnInfo(name = StreamEntity.STREAM_THUMBNAIL_URL)
final public String thumbnailUrl;
@ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID)
final public long streamId;
@ColumnInfo(name = StreamStatisticsEntry.STREAM_LATEST_DATE)
final public Date latestAccessDate;
@ColumnInfo(name = StreamStatisticsEntry.STREAM_WATCH_COUNT)
final public long watchCount;
public StreamStatisticsEntry(long uid, int serviceId, String url, String title,
StreamType streamType, long duration, String uploader,
String thumbnailUrl, long streamId, Date latestAccessDate,
long watchCount) {
this.uid = uid;
this.serviceId = serviceId;
this.url = url;
this.title = title;
this.streamType = streamType;
this.duration = duration;
this.uploader = uploader;
this.thumbnailUrl = thumbnailUrl;
this.streamId = streamId;
this.latestAccessDate = latestAccessDate;
this.watchCount = watchCount;
}
public StreamInfoItem toStreamInfoItem() {
StreamInfoItem item = new StreamInfoItem(serviceId, url, title, streamType);
item.setDuration(duration);
item.setUploaderName(uploader);
item.setThumbnailUrl(thumbnailUrl);
return item;
}
@Override
public LocalItemType getLocalItemType() {
return LocalItemType.STATISTIC_STREAM_ITEM;
}
}

View File

@@ -0,0 +1,100 @@
package org.schabi.newpipe.database.stream.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_SERVICE_ID;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
@Dao
public abstract class StreamDAO implements BasicDAO<StreamEntity> {
@Override
@Query("SELECT * FROM " + STREAM_TABLE)
public abstract Flowable<List<StreamEntity>> getAll();
@Override
@Query("DELETE FROM " + STREAM_TABLE)
public abstract int deleteAll();
@Override
@Query("SELECT * FROM " + STREAM_TABLE + " WHERE " + STREAM_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<StreamEntity>> listByService(int serviceId);
@Query("SELECT * FROM " + STREAM_TABLE + " WHERE " +
STREAM_URL + " = :url AND " +
STREAM_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<StreamEntity>> getStream(long serviceId, String url);
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract void silentInsertAllInternal(final List<StreamEntity> streams);
@Query("SELECT " + STREAM_ID + " FROM " + STREAM_TABLE + " WHERE " +
STREAM_URL + " = :url AND " +
STREAM_SERVICE_ID + " = :serviceId")
abstract Long getStreamIdInternal(long serviceId, String url);
@Transaction
public long upsert(StreamEntity stream) {
final Long streamIdCandidate = getStreamIdInternal(stream.getServiceId(), stream.getUrl());
if (streamIdCandidate == null) {
return insert(stream);
} else {
stream.setUid(streamIdCandidate);
update(stream);
return streamIdCandidate;
}
}
@Transaction
public List<Long> upsertAll(List<StreamEntity> streams) {
silentInsertAllInternal(streams);
final List<Long> streamIds = new ArrayList<>(streams.size());
for (StreamEntity stream : streams) {
final Long streamId = getStreamIdInternal(stream.getServiceId(), stream.getUrl());
if (streamId == null) {
throw new IllegalStateException("StreamID cannot be null just after insertion.");
}
streamIds.add(streamId);
stream.setUid(streamId);
}
update(streams);
return streamIds;
}
@Query("DELETE FROM " + STREAM_TABLE + " WHERE " + STREAM_ID +
" NOT IN " +
"(SELECT DISTINCT " + STREAM_ID + " FROM " + STREAM_TABLE +
" LEFT JOIN " + STREAM_HISTORY_TABLE +
" ON " + STREAM_ID + " = " +
StreamHistoryEntity.STREAM_HISTORY_TABLE + "." + StreamHistoryEntity.JOIN_STREAM_ID +
" LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE +
" ON " + STREAM_ID + " = " +
PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE + "." + PlaylistStreamEntity.JOIN_STREAM_ID +
")")
public abstract int deleteOrphans();
}

View File

@@ -0,0 +1,48 @@
package org.schabi.newpipe.database.stream.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
@Dao
public abstract class StreamStateDAO implements BasicDAO<StreamStateEntity> {
@Override
@Query("SELECT * FROM " + STREAM_STATE_TABLE)
public abstract Flowable<List<StreamStateEntity>> getAll();
@Override
@Query("DELETE FROM " + STREAM_STATE_TABLE)
public abstract int deleteAll();
@Override
public Flowable<List<StreamStateEntity>> listByService(int serviceId) {
throw new UnsupportedOperationException();
}
@Query("SELECT * FROM " + STREAM_STATE_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
public abstract Flowable<List<StreamStateEntity>> getState(final long streamId);
@Query("DELETE FROM " + STREAM_STATE_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
public abstract int deleteState(final long streamId);
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract void silentInsertInternal(final StreamStateEntity streamState);
@Transaction
public long upsert(StreamStateEntity stream) {
silentInsertInternal(stream);
return update(stream);
}
}

View File

@@ -0,0 +1,153 @@
package org.schabi.newpipe.database.stream.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.util.Constants;
import java.io.Serializable;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_SERVICE_ID;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
@Entity(tableName = STREAM_TABLE,
indices = {@Index(value = {STREAM_SERVICE_ID, STREAM_URL}, unique = true)})
public class StreamEntity implements Serializable {
final public static String STREAM_TABLE = "streams";
final public static String STREAM_ID = "uid";
final public static String STREAM_SERVICE_ID = "service_id";
final public static String STREAM_URL = "url";
final public static String STREAM_TITLE = "title";
final public static String STREAM_TYPE = "stream_type";
final public static String STREAM_DURATION = "duration";
final public static String STREAM_UPLOADER = "uploader";
final public static String STREAM_THUMBNAIL_URL = "thumbnail_url";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = STREAM_ID)
private long uid = 0;
@ColumnInfo(name = STREAM_SERVICE_ID)
private int serviceId = Constants.NO_SERVICE_ID;
@ColumnInfo(name = STREAM_URL)
private String url;
@ColumnInfo(name = STREAM_TITLE)
private String title;
@ColumnInfo(name = STREAM_TYPE)
private StreamType streamType;
@ColumnInfo(name = STREAM_DURATION)
private Long duration;
@ColumnInfo(name = STREAM_UPLOADER)
private String uploader;
@ColumnInfo(name = STREAM_THUMBNAIL_URL)
private String thumbnailUrl;
public StreamEntity(final int serviceId, final String title, final String url,
final StreamType streamType, final String thumbnailUrl, final String uploader,
final long duration) {
this.serviceId = serviceId;
this.title = title;
this.url = url;
this.streamType = streamType;
this.thumbnailUrl = thumbnailUrl;
this.uploader = uploader;
this.duration = duration;
}
@Ignore
public StreamEntity(final StreamInfoItem item) {
this(item.getServiceId(), item.getName(), item.getUrl(), item.getStreamType(), item.getThumbnailUrl(),
item.getUploaderName(), item.getDuration());
}
@Ignore
public StreamEntity(final StreamInfo info) {
this(info.getServiceId(), info.getName(), info.getUrl(), info.getStreamType(), info.getThumbnailUrl(),
info.getUploaderName(), info.getDuration());
}
@Ignore
public StreamEntity(final PlayQueueItem item) {
this(item.getServiceId(), item.getTitle(), item.getUrl(), item.getStreamType(),
item.getThumbnailUrl(), item.getUploader(), item.getDuration());
}
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public int getServiceId() {
return serviceId;
}
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public StreamType getStreamType() {
return streamType;
}
public void setStreamType(StreamType type) {
this.streamType = type;
}
public Long getDuration() {
return duration;
}
public void setDuration(Long duration) {
this.duration = duration;
}
public String getUploader() {
return uploader;
}
public void setUploader(String uploader) {
this.uploader = uploader;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
}

View File

@@ -0,0 +1,51 @@
package org.schabi.newpipe.database.stream.model;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
import static android.arch.persistence.room.ForeignKey.CASCADE;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
@Entity(tableName = STREAM_STATE_TABLE,
primaryKeys = {JOIN_STREAM_ID},
foreignKeys = {
@ForeignKey(entity = StreamEntity.class,
parentColumns = StreamEntity.STREAM_ID,
childColumns = JOIN_STREAM_ID,
onDelete = CASCADE, onUpdate = CASCADE)
})
public class StreamStateEntity {
final public static String STREAM_STATE_TABLE = "stream_state";
final public static String JOIN_STREAM_ID = "stream_id";
final public static String STREAM_PROGRESS_TIME = "progress_time";
@ColumnInfo(name = JOIN_STREAM_ID)
private long streamUid;
@ColumnInfo(name = STREAM_PROGRESS_TIME)
private long progressTime;
public StreamStateEntity(long streamUid, long progressTime) {
this.streamUid = streamUid;
this.progressTime = progressTime;
}
public long getStreamUid() {
return streamUid;
}
public void setStreamUid(long streamUid) {
this.streamUid = streamUid;
}
public long getProgressTime() {
return progressTime;
}
public void setProgressTime(long progressTime) {
this.progressTime = progressTime;
}
}

View File

@@ -0,0 +1,69 @@
package org.schabi.newpipe.database.subscription;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_UID;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_URL;
@Dao
public abstract class SubscriptionDAO implements BasicDAO<SubscriptionEntity> {
@Override
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE)
public abstract Flowable<List<SubscriptionEntity>> getAll();
@Override
@Query("DELETE FROM " + SUBSCRIPTION_TABLE)
public abstract int deleteAll();
@Override
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE + " WHERE " + SUBSCRIPTION_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<SubscriptionEntity>> listByService(int serviceId);
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE + " WHERE " +
SUBSCRIPTION_URL + " LIKE :url AND " +
SUBSCRIPTION_SERVICE_ID + " = :serviceId")
public abstract Flowable<List<SubscriptionEntity>> getSubscription(int serviceId, String url);
@Query("SELECT " + SUBSCRIPTION_UID + " FROM " + SUBSCRIPTION_TABLE + " WHERE " +
SUBSCRIPTION_URL + " LIKE :url AND " +
SUBSCRIPTION_SERVICE_ID + " = :serviceId")
abstract Long getSubscriptionIdInternal(int serviceId, String url);
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract Long insertInternal(final SubscriptionEntity entities);
@Transaction
public List<SubscriptionEntity> upsertAll(List<SubscriptionEntity> entities) {
for (SubscriptionEntity entity : entities) {
Long uid = insertInternal(entity);
if (uid != -1) {
entity.setUid(uid);
continue;
}
uid = getSubscriptionIdInternal(entity.getServiceId(), entity.getUrl());
entity.setUid(uid);
if (uid == -1) {
throw new IllegalStateException("Invalid subscription id (-1)");
}
update(entity);
}
return entities;
}
}

View File

@@ -0,0 +1,136 @@
package org.schabi.newpipe.database.subscription;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.util.Constants;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_URL;
@Entity(tableName = SUBSCRIPTION_TABLE,
indices = {@Index(value = {SUBSCRIPTION_SERVICE_ID, SUBSCRIPTION_URL}, unique = true)})
public class SubscriptionEntity {
final static String SUBSCRIPTION_UID = "uid";
final static String SUBSCRIPTION_TABLE = "subscriptions";
final static String SUBSCRIPTION_SERVICE_ID = "service_id";
final static String SUBSCRIPTION_URL = "url";
final static String SUBSCRIPTION_NAME = "name";
final static String SUBSCRIPTION_AVATAR_URL = "avatar_url";
final static String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
final static String SUBSCRIPTION_DESCRIPTION = "description";
@PrimaryKey(autoGenerate = true)
private long uid = 0;
@ColumnInfo(name = SUBSCRIPTION_SERVICE_ID)
private int serviceId = Constants.NO_SERVICE_ID;
@ColumnInfo(name = SUBSCRIPTION_URL)
private String url;
@ColumnInfo(name = SUBSCRIPTION_NAME)
private String name;
@ColumnInfo(name = SUBSCRIPTION_AVATAR_URL)
private String avatarUrl;
@ColumnInfo(name = SUBSCRIPTION_SUBSCRIBER_COUNT)
private Long subscriberCount;
@ColumnInfo(name = SUBSCRIPTION_DESCRIPTION)
private String description;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public int getServiceId() {
return serviceId;
}
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Long getSubscriberCount() {
return subscriberCount;
}
public void setSubscriberCount(Long subscriberCount) {
this.subscriberCount = subscriberCount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Ignore
public void setData(final String name,
final String avatarUrl,
final String description,
final Long subscriberCount) {
this.setName(name);
this.setAvatarUrl(avatarUrl);
this.setDescription(description);
this.setSubscriberCount(subscriberCount);
}
@Ignore
public ChannelInfoItem toChannelInfoItem() {
ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
item.setThumbnailUrl(getAvatarUrl());
item.setSubscriberCount(getSubscriberCount());
item.setDescription(getDescription());
return item;
}
@Ignore
public static SubscriptionEntity from(@NonNull ChannelInfo info) {
SubscriptionEntity result = new SubscriptionEntity();
result.setServiceId(info.getServiceId());
result.setUrl(info.getUrl());
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount());
return result;
}
}

View File

@@ -0,0 +1,90 @@
package org.schabi.newpipe.download;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.ViewTreeObserver;
import org.schabi.newpipe.R;
import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ThemeHelper;
import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.fragment.AllMissionsFragment;
import us.shandian.giga.ui.fragment.MissionsFragment;
public class DownloadActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Service
Intent i = new Intent();
i.setClass(this, DownloadManagerService.class);
startService(i);
ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_downloader);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.downloads_title);
actionBar.setDisplayShowTitleEnabled(true);
}
// Fragment
getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
updateFragments();
getWindow().getDecorView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
private void updateFragments() {
MissionsFragment fragment = new AllMissionsFragment();
getFragmentManager().beginTransaction()
.replace(R.id.frame, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.download_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
onBackPressed();
return true;
}
case R.id.action_settings: {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,275 @@
package org.schabi.newpipe.download;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.detail.SpinnerToolbarAdapter;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.util.FilenameUtils;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import us.shandian.giga.service.DownloadManagerService;
public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
private static final String TAG = "DialogFragment";
private static final boolean DEBUG = MainActivity.DEBUG;
private static final String INFO_KEY = "info_key";
private static final String SORTED_VIDEOS_LIST_KEY = "sorted_videos_list_key";
private static final String SELECTED_VIDEO_KEY = "selected_video_key";
private static final String SELECTED_AUDIO_KEY = "selected_audio_key";
private StreamInfo currentInfo;
private ArrayList<VideoStream> sortedStreamVideosList;
private int selectedVideoIndex;
private int selectedAudioIndex;
private EditText nameEditText;
private Spinner streamsSpinner;
private RadioGroup radioVideoAudioGroup;
private TextView threadsCountTextView;
private SeekBar threadsSeekBar;
public static DownloadDialog newInstance(StreamInfo info, ArrayList<VideoStream> sortedStreamVideosList, int selectedVideoIndex) {
DownloadDialog dialog = new DownloadDialog();
dialog.setInfo(info, sortedStreamVideosList, selectedVideoIndex);
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
return dialog;
}
private void setInfo(StreamInfo info, ArrayList<VideoStream> sortedStreamVideosList, int selectedVideoIndex) {
this.currentInfo = info;
this.selectedVideoIndex = selectedVideoIndex;
this.sortedStreamVideosList = sortedStreamVideosList;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
if (!PermissionHelper.checkStoragePermissions(getActivity())) {
getDialog().dismiss();
return;
}
if (savedInstanceState != null) {
Serializable serial = savedInstanceState.getSerializable(INFO_KEY);
if (serial instanceof StreamInfo) currentInfo = (StreamInfo) serial;
serial = savedInstanceState.getSerializable(SORTED_VIDEOS_LIST_KEY);
if (serial instanceof ArrayList) { //noinspection unchecked
sortedStreamVideosList = (ArrayList<VideoStream>) serial;
}
selectedVideoIndex = savedInstanceState.getInt(SELECTED_VIDEO_KEY, 0);
selectedAudioIndex = savedInstanceState.getInt(SELECTED_AUDIO_KEY, 0);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView() called with: inflater = [" + inflater + "], container = [" + container + "], savedInstanceState = [" + savedInstanceState + "]");
return inflater.inflate(R.layout.dialog_url, container);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
nameEditText = view.findViewById(R.id.file_name);
nameEditText.setText(FilenameUtils.createFilename(getContext(), currentInfo.getName()));
selectedAudioIndex = ListHelper.getDefaultAudioFormat(getContext(), currentInfo.getAudioStreams());
streamsSpinner = view.findViewById(R.id.quality_spinner);
streamsSpinner.setOnItemSelectedListener(this);
threadsCountTextView = view.findViewById(R.id.threads_count);
threadsSeekBar = view.findViewById(R.id.threads);
radioVideoAudioGroup = view.findViewById(R.id.video_audio_group);
radioVideoAudioGroup.setOnCheckedChangeListener(this);
initToolbar(view.<Toolbar>findViewById(R.id.toolbar));
checkDownloadOptions(view);
setupVideoSpinner(sortedStreamVideosList, streamsSpinner);
int def = 3;
threadsCountTextView.setText(String.valueOf(def));
threadsSeekBar.setProgress(def - 1);
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
threadsCountTextView.setText(String.valueOf(progress + 1));
}
@Override
public void onStartTrackingTouch(SeekBar p1) {
}
@Override
public void onStopTrackingTouch(SeekBar p1) {
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(INFO_KEY, currentInfo);
outState.putSerializable(SORTED_VIDEOS_LIST_KEY, sortedStreamVideosList);
outState.putInt(SELECTED_VIDEO_KEY, selectedVideoIndex);
outState.putInt(SELECTED_AUDIO_KEY, selectedAudioIndex);
}
/*//////////////////////////////////////////////////////////////////////////
// Inits
//////////////////////////////////////////////////////////////////////////*/
private void initToolbar(Toolbar toolbar) {
if (DEBUG) Log.d(TAG, "initToolbar() called with: toolbar = [" + toolbar + "]");
toolbar.setTitle(R.string.download_dialog_title);
toolbar.setNavigationIcon(ThemeHelper.isLightThemeSelected(getActivity()) ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
toolbar.inflateMenu(R.menu.dialog_url);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getDialog().dismiss();
}
});
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.okay) {
downloadSelected();
return true;
} else return false;
}
});
}
public void setupAudioSpinner(final List<AudioStream> audioStreams, Spinner spinner) {
String[] items = new String[audioStreams.size()];
for (int i = 0; i < audioStreams.size(); i++) {
AudioStream audioStream = audioStreams.get(i);
items[i] = audioStream.getFormat().getName() + " " + audioStream.getAverageBitrate() + "kbps";
}
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, items);
spinner.setAdapter(itemAdapter);
spinner.setSelection(selectedAudioIndex);
}
public void setupVideoSpinner(final List<VideoStream> videoStreams, Spinner spinner) {
spinner.setAdapter(new SpinnerToolbarAdapter(getContext(), videoStreams, true));
spinner.setSelection(selectedVideoIndex);
}
/*//////////////////////////////////////////////////////////////////////////
// Radio group Video&Audio options - Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
if (DEBUG) Log.d(TAG, "onCheckedChanged() called with: group = [" + group + "], checkedId = [" + checkedId + "]");
switch (checkedId) {
case R.id.audio_button:
setupAudioSpinner(currentInfo.getAudioStreams(), streamsSpinner);
break;
case R.id.video_button:
setupVideoSpinner(sortedStreamVideosList, streamsSpinner);
break;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Streams Spinner Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (DEBUG) Log.d(TAG, "onItemSelected() called with: parent = [" + parent + "], view = [" + view + "], position = [" + position + "], id = [" + id + "]");
switch (radioVideoAudioGroup.getCheckedRadioButtonId()) {
case R.id.audio_button:
selectedAudioIndex = position;
break;
case R.id.video_button:
selectedVideoIndex = position;
break;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
protected void checkDownloadOptions(View view) {
RadioButton audioButton = view.findViewById(R.id.audio_button);
RadioButton videoButton = view.findViewById(R.id.video_button);
if (currentInfo.getAudioStreams() == null || currentInfo.getAudioStreams().size() == 0) {
audioButton.setVisibility(View.GONE);
videoButton.setChecked(true);
} else if (sortedStreamVideosList == null || sortedStreamVideosList.size() == 0) {
videoButton.setVisibility(View.GONE);
audioButton.setChecked(true);
}
}
private void downloadSelected() {
String url, location;
String fileName = nameEditText.getText().toString().trim();
if (fileName.isEmpty()) fileName = FilenameUtils.createFilename(getContext(), currentInfo.getName());
boolean isAudio = radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button;
if (isAudio) {
url = currentInfo.getAudioStreams().get(selectedAudioIndex).getUrl();
location = NewPipeSettings.getAudioDownloadPath(getContext());
fileName += "." + currentInfo.getAudioStreams().get(selectedAudioIndex).getFormat().getSuffix();
} else {
url = sortedStreamVideosList.get(selectedVideoIndex).getUrl();
location = NewPipeSettings.getVideoDownloadPath(getContext());
fileName += "." + sortedStreamVideosList.get(selectedVideoIndex).getFormat().getSuffix();
}
DownloadManagerService.startMission(getContext(), url, location, fileName, isAudio, threadsSeekBar.getProgress() + 1);
getDialog().dismiss();
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.fragments;
/**
* Indicates that the current fragment can handle back presses
*/
public interface BackPressable {
/**
* A back press was delegated to this fragment
*
* @return if the back press was handled
*/
boolean onBackPressed();
}

View File

@@ -0,0 +1,261 @@
package org.schabi.newpipe.fragments;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.jakewharton.rxbinding2.view.RxView;
import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.InfoCache;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import icepick.State;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public abstract class BaseStateFragment<I> extends BaseFragment implements ViewContract<I> {
@State
protected AtomicBoolean wasLoading = new AtomicBoolean();
protected AtomicBoolean isLoading = new AtomicBoolean();
@Nullable
protected View emptyStateView;
@Nullable
protected ProgressBar loadingProgressBar;
protected View errorPanelRoot;
protected Button errorButtonRetry;
protected TextView errorTextView;
@State
protected boolean useAsFrontPage = false;
@Override
public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
doInitialLoadLogic();
}
@Override
public void onPause() {
super.onPause();
wasLoading.set(isLoading.get());
}
public void useAsFrontPage(boolean value) {
useAsFrontPage = value;
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
emptyStateView = rootView.findViewById(R.id.empty_state_view);
loadingProgressBar = rootView.findViewById(R.id.loading_progress_bar);
errorPanelRoot = rootView.findViewById(R.id.error_panel);
errorButtonRetry = rootView.findViewById(R.id.error_button_retry);
errorTextView = rootView.findViewById(R.id.error_message_view);
}
@Override
protected void initListeners() {
super.initListeners();
RxView.clicks(errorButtonRetry)
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
onRetryButtonClicked();
}
});
}
protected void onRetryButtonClicked() {
reloadContent();
}
public void reloadContent() {
startLoading(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Load
//////////////////////////////////////////////////////////////////////////*/
protected void doInitialLoadLogic() {
startLoading(true);
}
protected void startLoading(boolean forceLoad) {
if (DEBUG) Log.d(TAG, "startLoading() called with: forceLoad = [" + forceLoad + "]");
showLoading();
isLoading.set(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
if (emptyStateView != null) animateView(emptyStateView, false, 150);
if (loadingProgressBar != null) animateView(loadingProgressBar, true, 400);
animateView(errorPanelRoot, false, 150);
}
@Override
public void hideLoading() {
if (emptyStateView != null) animateView(emptyStateView, false, 150);
if (loadingProgressBar != null) animateView(loadingProgressBar, false, 0);
animateView(errorPanelRoot, false, 150);
}
@Override
public void showEmptyState() {
isLoading.set(false);
if (emptyStateView != null) animateView(emptyStateView, true, 200);
if (loadingProgressBar != null) animateView(loadingProgressBar, false, 0);
animateView(errorPanelRoot, false, 150);
}
@Override
public void showError(String message, boolean showRetryButton) {
if (DEBUG) Log.d(TAG, "showError() called with: message = [" + message + "], showRetryButton = [" + showRetryButton + "]");
isLoading.set(false);
InfoCache.getInstance().clearCache();
hideLoading();
errorTextView.setText(message);
if (showRetryButton) animateView(errorButtonRetry, true, 600);
else animateView(errorButtonRetry, false, 0);
animateView(errorPanelRoot, true, 300);
}
@Override
public void handleResult(I result) {
if (DEBUG) Log.d(TAG, "handleResult() called with: result = [" + result + "]");
hideLoading();
}
/*//////////////////////////////////////////////////////////////////////////
// Error handling
//////////////////////////////////////////////////////////////////////////*/
/**
* Default implementation handles some general exceptions
*
* @return if the exception was handled
*/
protected boolean onError(Throwable exception) {
if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]");
isLoading.set(false);
if (isDetached() || isRemoving()) {
if (DEBUG) Log.w(TAG, "onError() is detached or removing = [" + exception + "]");
return true;
}
if (ExtractorHelper.isInterruptedCaused(exception)) {
if (DEBUG) Log.w(TAG, "onError() isInterruptedCaused! = [" + exception + "]");
return true;
}
if (exception instanceof ReCaptchaException) {
onReCaptchaException();
return true;
} else if (exception instanceof IOException) {
showError(getString(R.string.network_error), true);
return true;
}
return false;
}
public void onReCaptchaException() {
if (DEBUG) Log.d(TAG, "onReCaptchaException() called");
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
// Starting ReCaptcha Challenge Activity
startActivityForResult(new Intent(activity, ReCaptchaActivity.class), ReCaptchaActivity.RECAPTCHA_REQUEST);
showError(getString(R.string.recaptcha_request_toast), false);
}
public void onUnrecoverableError(Throwable exception, UserAction userAction, String serviceName, String request, @StringRes int errorId) {
onUnrecoverableError(Collections.singletonList(exception), userAction, serviceName, request, errorId);
}
public void onUnrecoverableError(List<Throwable> exception, UserAction userAction, String serviceName, String request, @StringRes int errorId) {
if (DEBUG) Log.d(TAG, "onUnrecoverableError() called with: exception = [" + exception + "]");
if (serviceName == null) serviceName = "none";
if (request == null) request = "none";
ErrorActivity.reportError(getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
}
public void showSnackBarError(Throwable exception, UserAction userAction, String serviceName, String request, @StringRes int errorId) {
showSnackBarError(Collections.singletonList(exception), userAction, serviceName, request, errorId);
}
/**
* Show a SnackBar and only call ErrorActivity#reportError IF we a find a valid view (otherwise the error screen appears)
*/
public void showSnackBarError(List<Throwable> exception, UserAction userAction, String serviceName, String request, @StringRes int errorId) {
if (DEBUG) {
Log.d(TAG, "showSnackBarError() called with: exception = [" + exception + "], userAction = [" + userAction + "], request = [" + request + "], errorId = [" + errorId + "]");
}
View rootView = activity != null ? activity.findViewById(android.R.id.content) : null;
if (rootView == null && getView() != null) rootView = getView();
if (rootView == null) return;
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
protected void openUrlInBrowser(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title)));
}
protected void shareUrl(String subject, String url) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
}
}

View File

@@ -0,0 +1,37 @@
package org.schabi.newpipe.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R;
public class BlankFragment extends BaseFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
if(activity != null && activity.getSupportActionBar() != null) {
activity.getSupportActionBar()
.setTitle("NewPipe");
}
return inflater.inflate(R.layout.fragment_blank, container, false);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
if(activity != null && activity.getSupportActionBar() != null) {
activity.getSupportActionBar()
.setTitle("NewPipe");
}
// leave this inline. Will make it harder for copy cats.
// If you are a Copy cat FUCK YOU.
// I WILL FIND YOU, AND I WILL ...
}
}
}

View File

@@ -0,0 +1,276 @@
package org.schabi.newpipe.fragments;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.local.bookmark.BookmarkFragment;
import org.schabi.newpipe.fragments.subscription.SubscriptionFragment;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.ThemeHelper;
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
public int currentServiceId = -1;
private ViewPager viewPager;
/*//////////////////////////////////////////////////////////////////////////
// Constants
//////////////////////////////////////////////////////////////////////////*/
private static final int FALLBACK_SERVICE_ID = ServiceList.YouTube.getServiceId();
private static final String FALLBACK_CHANNEL_URL = "https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ";
private static final String FALLBACK_CHANNEL_NAME = "Music";
private static final String FALLBACK_KIOSK_ID = "Trending";
private static final int KIOSK_MENU_OFFSET = 2000;
/*//////////////////////////////////////////////////////////////////////////
// Fragment's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
currentServiceId = ServiceHelper.getSelectedServiceId(activity);
return inflater.inflate(R.layout.fragment_main, container, false);
}
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
TabLayout tabLayout = rootView.findViewById(R.id.main_tab_layout);
viewPager = rootView.findViewById(R.id.pager);
/* Nested fragment, use child fragment here to maintain backstack in view pager. */
PagerAdapter adapter = new PagerAdapter(getChildFragmentManager());
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount());
tabLayout.setupWithViewPager(viewPager);
int channelIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_channel);
int whatsHotIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_hot);
int bookmarkIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_bookmark);
if (isSubscriptionsPageOnlySelected()) {
tabLayout.getTabAt(0).setIcon(channelIcon);
tabLayout.getTabAt(1).setIcon(bookmarkIcon);
} else {
tabLayout.getTabAt(0).setIcon(whatsHotIcon);
tabLayout.getTabAt(1).setIcon(channelIcon);
tabLayout.getTabAt(2).setIcon(bookmarkIcon);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
inflater.inflate(R.menu.main_fragment_menu, menu);
SubMenu kioskMenu = menu.addSubMenu(Menu.NONE, Menu.NONE, 200, getString(R.string.kiosk));
try {
createKioskMenu(kioskMenu, inflater);
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
}
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
NavigationHelper.openSearchFragment(getFragmentManager(), ServiceHelper.getSelectedServiceId(activity), "");
return true;
}
return super.onOptionsItemSelected(item);
}
/*//////////////////////////////////////////////////////////////////////////
// Tabs
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
private class PagerAdapter extends FragmentPagerAdapter {
PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return isSubscriptionsPageOnlySelected() ? new SubscriptionFragment() : getMainPageFragment();
case 1:
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
return new BookmarkFragment();
} else {
return new SubscriptionFragment();
}
case 2:
return new BookmarkFragment();
default:
return new BlankFragment();
}
}
@Override
public CharSequence getPageTitle(int position) {
//return getString(this.tabTitles[position]);
return "";
}
@Override
public int getCount() {
return isSubscriptionsPageOnlySelected() ? 2 : 3;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Main page content
//////////////////////////////////////////////////////////////////////////*/
private boolean isSubscriptionsPageOnlySelected() {
return PreferenceManager.getDefaultSharedPreferences(activity)
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key));
}
private Fragment getMainPageFragment() {
if (getActivity() == null) return new BlankFragment();
try {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(getActivity());
final String setMainPage = preferences.getString(getString(R.string.main_page_content_key),
getString(R.string.main_page_selectd_kiosk_id));
if (setMainPage.equals(getString(R.string.blank_page_key))) {
return new BlankFragment();
} else if (setMainPage.equals(getString(R.string.kiosk_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String kioskId = preferences.getString(getString(R.string.main_page_selectd_kiosk_id),
FALLBACK_KIOSK_ID);
KioskFragment fragment = KioskFragment.getInstance(serviceId, kioskId);
fragment.useAsFrontPage(true);
return fragment;
} else if (setMainPage.equals(getString(R.string.feed_page_key))) {
FeedFragment fragment = new FeedFragment();
fragment.useAsFrontPage(true);
return fragment;
} else if (setMainPage.equals(getString(R.string.channel_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String url = preferences.getString(getString(R.string.main_page_selected_channel_url),
FALLBACK_CHANNEL_URL);
String name = preferences.getString(getString(R.string.main_page_selected_channel_name),
FALLBACK_CHANNEL_NAME);
ChannelFragment fragment = ChannelFragment.getInstance(serviceId, url, name);
fragment.useAsFrontPage(true);
return fragment;
} else {
return new BlankFragment();
}
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return new BlankFragment();
}
}
/*//////////////////////////////////////////////////////////////////////////
// Select Kiosk
//////////////////////////////////////////////////////////////////////////*/
private void createKioskMenu(Menu menu, MenuInflater menuInflater)
throws Exception {
StreamingService service = NewPipe.getService(currentServiceId);
KioskList kl = service.getKioskList();
int i = 0;
for (final String ks : kl.getAvailableKiosks()) {
menu.add(0, KIOSK_MENU_OFFSET + i, Menu.NONE,
KioskTranslator.getTranslatedKioskName(ks, getContext()))
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
try {
NavigationHelper.openKioskFragment(getFragmentManager(), currentServiceId, ks);
} catch (Exception e) {
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
}
return true;
}
});
i++;
}
}
}

View File

@@ -0,0 +1,43 @@
package org.schabi.newpipe.fragments;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
/**
* Recycler view scroll listener which calls the method {@link #onScrolledDown(RecyclerView)}
* if the view is scrolled below the last item.
*/
public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollListener {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
int pastVisibleItems = 0, visibleItemCount, totalItemCount;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
visibleItemCount = layoutManager.getChildCount();
totalItemCount = layoutManager.getItemCount();
// Already covers the GridLayoutManager case
if (layoutManager instanceof LinearLayoutManager) {
pastVisibleItems = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int[] positions = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null);
if (positions != null && positions.length > 0) pastVisibleItems = positions[0];
}
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
onScrolledDown(recyclerView);
}
}
}
/**
* Called when the recycler view is scrolled below the last item.
*
* @param recyclerView the recycler view
*/
public abstract void onScrolledDown(RecyclerView recyclerView);
}

View File

@@ -0,0 +1,10 @@
package org.schabi.newpipe.fragments;
public interface ViewContract<I> {
void showLoading();
void hideLoading();
void showEmptyState();
void showError(String message, boolean showRetryButton);
void handleResult(I result);
}

View File

@@ -0,0 +1,74 @@
package org.schabi.newpipe.fragments.detail;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.VideoStream;
import java.util.List;
public class SpinnerToolbarAdapter extends BaseAdapter {
private final List<VideoStream> videoStreams;
private final boolean showIconNoAudio;
private final Context context;
public SpinnerToolbarAdapter(Context context, List<VideoStream> videoStreams, boolean showIconNoAudio) {
this.context = context;
this.videoStreams = videoStreams;
this.showIconNoAudio = showIconNoAudio;
}
@Override
public int getCount() {
return videoStreams.size();
}
@Override
public Object getItem(int position) {
return videoStreams.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent, true);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getCustomView(((Spinner) parent).getSelectedItemPosition(), convertView, parent, false);
}
private View getCustomView(int position, View convertView, ViewGroup parent, boolean isDropdownItem) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.resolutions_spinner_item, parent, false);
}
ImageView woSoundIcon = convertView.findViewById(R.id.wo_sound_icon);
TextView text = convertView.findViewById(android.R.id.text1);
VideoStream item = (VideoStream) getItem(position);
text.setText(item.getFormat().getName() + " " + item.getResolution());
int visibility = !showIconNoAudio ? View.GONE
: item.isVideoOnly ? View.VISIBLE
: isDropdownItem ? View.INVISIBLE
: View.GONE;
woSoundIcon.setVisibility(visibility);
return convertView;
}
}

View File

@@ -0,0 +1,36 @@
package org.schabi.newpipe.fragments.detail;
import java.io.Serializable;
class StackItem implements Serializable {
private int serviceId;
private String title;
private String url;
StackItem(int serviceId, String url, String title) {
this.serviceId = serviceId;
this.url = url;
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public int getServiceId() {
return serviceId;
}
public String getTitle() {
return title;
}
public String getUrl() {
return url;
}
@Override
public String toString() {
return getServiceId() + ":" + getUrl() + " > " + getTitle();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,288 @@
package org.schabi.newpipe.fragments.list;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
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.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.StateSaver;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implements ListViewContract<I, N>, StateSaver.WriteRead {
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
protected InfoListAdapter infoListAdapter;
protected RecyclerView itemsList;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
infoListAdapter = new InfoListAdapter(activity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onDestroy() {
super.onDestroy();
StateSaver.onDestroy(savedState);
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
protected StateSaver.SavedState savedState;
@Override
public String generateSuffix() {
// Naive solution, but it's good for now (the items don't change)
return "." + infoListAdapter.getItemsList().size() + ".list";
}
@Override
public void writeTo(Queue<Object> objectsToSave) {
objectsToSave.add(infoListAdapter.getItemsList());
}
@Override
@SuppressWarnings("unchecked")
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
infoListAdapter.getItemsList().clear();
infoListAdapter.getItemsList().addAll((List<InfoItem>) savedObjects.poll());
}
@Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
savedState = StateSaver.tryToSave(activity.isChangingConfigurations(), savedState, bundle, this);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle bundle) {
super.onRestoreInstanceState(bundle);
savedState = StateSaver.tryToRestore(bundle, this);
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
protected View getListHeader() {
return null;
}
protected View getListFooter() {
return activity.getLayoutInflater().inflate(R.layout.pignate_footer, itemsList, false);
}
protected RecyclerView.LayoutManager getListLayoutManager() {
return new LinearLayoutManager(activity);
}
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(getListLayoutManager());
infoListAdapter.setFooter(getListFooter());
infoListAdapter.setHeader(getListHeader());
itemsList.setAdapter(infoListAdapter);
}
protected void onItemSelected(InfoItem selectedItem) {
if (DEBUG) Log.d(TAG, "onItemSelected() called with: selectedItem = [" + selectedItem + "]");
}
@Override
protected void initListeners() {
super.initListeners();
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() {
@Override
public void selected(StreamInfoItem selectedItem) {
onItemSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
}
@Override
public void held(StreamInfoItem selectedItem) {
showStreamDialog(selectedItem);
}
});
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
@Override
public void selected(ChannelInfoItem selectedItem) {
onItemSelected(selectedItem);
NavigationHelper.openChannelFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
}
});
infoListAdapter.setOnPlaylistSelectedListener(new OnClickGesture<PlaylistInfoItem>() {
@Override
public void selected(PlaylistInfoItem selectedItem) {
onItemSelected(selectedItem);
NavigationHelper.openPlaylistFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
}
});
itemsList.clearOnScrollListeners();
itemsList.addOnScrollListener(new OnScrollBelowItemsListener() {
@Override
public void onScrolledDown(RecyclerView recyclerView) {
onScrollToBottom();
}
});
}
protected void onScrollToBottom() {
if (hasMoreItems() && !isLoading.get()) {
loadMoreItems();
}
}
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup),
context.getResources().getString(R.string.append_playlist)
};
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
case 2:
if (getFragmentManager() != null) {
PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item))
.show(getFragmentManager(), TAG);
}
break;
default:
break;
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setDisplayShowTitleEnabled(true);
if (useAsFrontPage) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
} else {
supportActionBar.setDisplayHomeAsUpEnabled(true);
}
}
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
protected abstract void loadMoreItems();
protected abstract boolean hasMoreItems();
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
// animateView(itemsList, false, 400);
}
@Override
public void hideLoading() {
super.hideLoading();
animateView(itemsList, true, 300);
}
@Override
public void showError(String message, boolean showRetryButton) {
super.showError(message, showRetryButton);
showListFooter(false);
animateView(itemsList, false, 200);
}
@Override
public void showEmptyState() {
super.showEmptyState();
showListFooter(false);
}
@Override
public void showListFooter(final boolean show) {
itemsList.post(() -> {
if (infoListAdapter != null && itemsList != null) {
infoListAdapter.showFooter(show);
}
});
}
@Override
public void handleNextItems(N result) {
isLoading.set(false);
}
}

View File

@@ -0,0 +1,193 @@
package org.schabi.newpipe.fragments.list;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.util.Constants;
import java.util.Queue;
import icepick.State;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public abstract class BaseListInfoFragment<I extends ListInfo>
extends BaseListFragment<I, ListExtractor.InfoItemsPage> {
@State
protected int serviceId = Constants.NO_SERVICE_ID;
@State
protected String name;
@State
protected String url;
protected I currentInfo;
protected String currentNextPageUrl;
protected Disposable currentWorker;
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
setTitle(name);
showListFooter(hasMoreItems());
}
@Override
public void onPause() {
super.onPause();
if (currentWorker != null) currentWorker.dispose();
}
@Override
public void onResume() {
super.onResume();
// Check if it was loading when the fragment was stopped/paused,
if (wasLoading.getAndSet(false)) {
if (hasMoreItems() && infoListAdapter.getItemsList().size() > 0) {
loadMoreItems();
} else {
doInitialLoadLogic();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (currentWorker != null) currentWorker.dispose();
currentWorker = null;
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void writeTo(Queue<Object> objectsToSave) {
super.writeTo(objectsToSave);
objectsToSave.add(currentInfo);
objectsToSave.add(currentNextPageUrl);
}
@Override
@SuppressWarnings("unchecked")
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
super.readFrom(savedObjects);
currentInfo = (I) savedObjects.poll();
currentNextPageUrl = (String) savedObjects.poll();
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
protected void doInitialLoadLogic() {
if (DEBUG) Log.d(TAG, "doInitialLoadLogic() called");
if (currentInfo == null) {
startLoading(false);
} else handleResult(currentInfo);
}
/**
* Implement the logic to load the info from the network.<br/>
* You can use the default implementations from {@link org.schabi.newpipe.util.ExtractorHelper}.
*
* @param forceLoad allow or disallow the result to come from the cache
*/
protected abstract Single<I> loadResult(boolean forceLoad);
@Override
public void startLoading(boolean forceLoad) {
super.startLoading(forceLoad);
showListFooter(false);
currentInfo = null;
if (currentWorker != null) currentWorker.dispose();
currentWorker = loadResult(forceLoad)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((@NonNull I result) -> {
isLoading.set(false);
currentInfo = result;
currentNextPageUrl = result.getNextPageUrl();
handleResult(result);
}, (@NonNull Throwable throwable) -> onError(throwable));
}
/**
* Implement the logic to load more items<br/>
* You can use the default implementations from {@link org.schabi.newpipe.util.ExtractorHelper}
*/
protected abstract Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic();
protected void loadMoreItems() {
isLoading.set(true);
if (currentWorker != null) currentWorker.dispose();
currentWorker = loadMoreItemsLogic()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((@io.reactivex.annotations.NonNull ListExtractor.InfoItemsPage InfoItemsPage) -> {
isLoading.set(false);
handleNextItems(InfoItemsPage);
}, (@io.reactivex.annotations.NonNull Throwable throwable) -> {
isLoading.set(false);
onError(throwable);
});
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
currentNextPageUrl = result.getNextPageUrl();
infoListAdapter.addInfoItemList(result.getItems());
showListFooter(hasMoreItems());
}
@Override
protected boolean hasMoreItems() {
return !TextUtils.isEmpty(currentNextPageUrl);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void handleResult(@NonNull I result) {
super.handleResult(result);
url = result.getUrl();
name = result.getName();
setTitle(name);
if (infoListAdapter.getItemsList().size() == 0) {
if (result.getRelatedItems().size() > 0) {
infoListAdapter.addInfoItemList(result.getRelatedItems());
showListFooter(hasMoreItems());
} else {
infoListAdapter.clearStreamItemList();
showEmptyState();
}
}
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
protected void setInitialData(int serviceId, String url, String name) {
this.serviceId = serviceId;
this.url = url;
this.name = !TextUtils.isEmpty(name) ? name : "";
}
}

View File

@@ -0,0 +1,9 @@
package org.schabi.newpipe.fragments.list;
import org.schabi.newpipe.fragments.ViewContract;
public interface ListViewContract<I, N> extends ViewContract<I> {
void showListFooter(boolean show);
void handleNextItems(N result);
}

View File

@@ -0,0 +1,506 @@
package org.schabi.newpipe.fragments.list.channel;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.jakewharton.rxbinding2.view.RxView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.ChannelPlayQueue;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.subscription.SubscriptionService;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor;
import static org.schabi.newpipe.util.AnimationUtils.animateTextColor;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
private CompositeDisposable disposables = new CompositeDisposable();
private Disposable subscribeButtonMonitor;
private SubscriptionService subscriptionService;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private ImageView headerChannelBanner;
private ImageView headerAvatarView;
private TextView headerTitleView;
private TextView headerSubscribersTextView;
private Button headerSubscribeButton;
private View playlistCtrl;
private LinearLayout headerPlayAllButton;
private LinearLayout headerPopupButton;
private LinearLayout headerBackgroundButton;
private MenuItem menuRssButton;
public static ChannelFragment getInstance(int serviceId, String url, String name) {
ChannelFragment instance = new ChannelFragment();
instance.setInitialData(serviceId, url, name);
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(activity != null
&& useAsFrontPage
&& isVisibleToUser) {
setTitle(currentInfo != null ? currentInfo.getName() : name);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
subscriptionService = SubscriptionService.getInstance(activity);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_channel, container, false);
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposables != null) disposables.clear();
if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose();
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
protected View getListHeader() {
headerRootLayout = activity.getLayoutInflater().inflate(R.layout.channel_header, itemsList, false);
headerChannelBanner = headerRootLayout.findViewById(R.id.channel_banner_image);
headerAvatarView = headerRootLayout.findViewById(R.id.channel_avatar_view);
headerTitleView = headerRootLayout.findViewById(R.id.channel_title_view);
headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view);
headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button);
playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control);
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
return headerRootLayout;
}
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Activity activity = getActivity();
final Context context = getContext();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup),
context.getResources().getString(R.string.start_here_on_main),
context.getResources().getString(R.string.start_here_on_background),
context.getResources().getString(R.string.start_here_on_popup),
};
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
break;
case 3:
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break;
default:
break;
}
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if(useAsFrontPage && supportActionBar != null) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
} else {
inflater.inflate(R.menu.menu_channel, menu);
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu +
"], inflater = [" + inflater + "]");
menuRssButton = menu.findItem(R.id.menu_item_rss);
}
}
private void openRssFeed() {
final ChannelInfo info = currentInfo;
if(info != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.getFeedUrl()));
startActivity(intent);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_rss:
openRssFeed();
break;
case R.id.menu_item_openInBrowser:
openUrlInBrowser(url);
break;
case R.id.menu_item_share:
shareUrl(name, url);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Channel Subscription
//////////////////////////////////////////////////////////////////////////*/
private static final int BUTTON_DEBOUNCE_INTERVAL = 100;
private void monitorSubscription(final ChannelInfo info) {
final Consumer<Throwable> onError = new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
animateView(headerSubscribeButton, false, 100);
showSnackBarError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Get subscription status", 0);
}
};
final Observable<List<SubscriptionEntity>> observable = subscriptionService.subscriptionTable()
.getSubscription(info.getServiceId(), info.getUrl())
.toObservable();
disposables.add(observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getSubscribeUpdateMonitor(info), onError));
disposables.add(observable
// Some updates are very rapid (when calling the updateSubscription(info), for example)
// so only update the UI for the latest emission ("sync" the subscribe button's state)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<SubscriptionEntity>>() {
@Override
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
updateSubscribeButton(!subscriptionEntities.isEmpty());
}
}, onError));
}
private Function<Object, Object> mapOnSubscribe(final SubscriptionEntity subscription) {
return new Function<Object, Object>() {
@Override
public Object apply(@NonNull Object o) throws Exception {
subscriptionService.subscriptionTable().insert(subscription);
return o;
}
};
}
private Function<Object, Object> mapOnUnsubscribe(final SubscriptionEntity subscription) {
return new Function<Object, Object>() {
@Override
public Object apply(@NonNull Object o) throws Exception {
subscriptionService.subscriptionTable().delete(subscription);
return o;
}
};
}
private void updateSubscription(final ChannelInfo info) {
if (DEBUG) Log.d(TAG, "updateSubscription() called with: info = [" + info + "]");
final Action onComplete = new Action() {
@Override
public void run() throws Exception {
if (DEBUG) Log.d(TAG, "Updated subscription: " + info.getUrl());
}
};
final Consumer<Throwable> onError = new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(info.getServiceId()), "Updating Subscription for " + info.getUrl(), R.string.subscription_update_failed);
}
};
disposables.add(subscriptionService.updateChannelInfo(info)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onComplete, onError));
}
private Disposable monitorSubscribeButton(final Button subscribeButton, final Function<Object, Object> action) {
final Consumer<Object> onNext = new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (DEBUG) Log.d(TAG, "Changed subscription status to this channel!");
}
};
final Consumer<Throwable> onError = new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Subscription Change", R.string.subscription_change_failed);
}
};
/* Emit clicks from main thread unto io thread */
return RxView.clicks(subscribeButton)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.io())
.debounce(BUTTON_DEBOUNCE_INTERVAL, TimeUnit.MILLISECONDS) // Ignore rapid clicks
.map(action)
.subscribe(onNext, onError);
}
private Consumer<List<SubscriptionEntity>> getSubscribeUpdateMonitor(final ChannelInfo info) {
return new Consumer<List<SubscriptionEntity>>() {
@Override
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
if (DEBUG)
Log.d(TAG, "subscriptionService.subscriptionTable.doOnNext() called with: subscriptionEntities = [" + subscriptionEntities + "]");
if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose();
if (subscriptionEntities.isEmpty()) {
if (DEBUG) Log.d(TAG, "No subscription to this channel!");
SubscriptionEntity channel = new SubscriptionEntity();
channel.setServiceId(info.getServiceId());
channel.setUrl(info.getUrl());
channel.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount());
subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnSubscribe(channel));
} else {
if (DEBUG) Log.d(TAG, "Found subscription to this channel!");
final SubscriptionEntity subscription = subscriptionEntities.get(0);
subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnUnsubscribe(subscription));
}
}
};
}
private void updateSubscribeButton(boolean isSubscribed) {
if (DEBUG) Log.d(TAG, "updateSubscribeButton() called with: isSubscribed = [" + isSubscribed + "]");
boolean isButtonVisible = headerSubscribeButton.getVisibility() == View.VISIBLE;
int backgroundDuration = isButtonVisible ? 300 : 0;
int textDuration = isButtonVisible ? 200 : 0;
int subscribeBackground = ContextCompat.getColor(activity, R.color.subscribe_background_color);
int subscribeText = ContextCompat.getColor(activity, R.color.subscribe_text_color);
int subscribedBackground = ContextCompat.getColor(activity, R.color.subscribed_background_color);
int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color);
if (!isSubscribed) {
headerSubscribeButton.setText(R.string.subscribe_button_title);
animateBackgroundColor(headerSubscribeButton, backgroundDuration, subscribedBackground, subscribeBackground);
animateTextColor(headerSubscribeButton, textDuration, subscribedText, subscribeText);
} else {
headerSubscribeButton.setText(R.string.subscribed_button_title);
animateBackgroundColor(headerSubscribeButton, backgroundDuration, subscribeBackground, subscribedBackground);
animateTextColor(headerSubscribeButton, textDuration, subscribeText, subscribedText);
}
animateView(headerSubscribeButton, AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, true, 100);
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
return ExtractorHelper.getMoreChannelItems(serviceId, url, currentNextPageUrl);
}
@Override
protected Single<ChannelInfo> loadResult(boolean forceLoad) {
return ExtractorHelper.getChannelInfo(serviceId, url, forceLoad);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
imageLoader.cancelDisplayTask(headerChannelBanner);
imageLoader.cancelDisplayTask(headerAvatarView);
animateView(headerSubscribeButton, false, 100);
}
@Override
public void handleResult(@NonNull ChannelInfo result) {
super.handleResult(result);
headerRootLayout.setVisibility(View.VISIBLE);
imageLoader.displayImage(result.getBannerUrl(), headerChannelBanner,
ImageDisplayConstants.DISPLAY_BANNER_OPTIONS);
imageLoader.displayImage(result.getAvatarUrl(), headerAvatarView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
if (result.getSubscriberCount() != -1) {
headerSubscribersTextView.setText(Localization.localizeSubscribersCount(activity, result.getSubscriberCount()));
headerSubscribersTextView.setVisibility(View.VISIBLE);
} else headerSubscribersTextView.setVisibility(View.GONE);
if (menuRssButton != null) menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl()));
playlistCtrl.setVisibility(View.VISIBLE);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
if (disposables != null) disposables.clear();
if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose();
updateSubscription(result);
monitorSubscription(result);
headerPlayAllButton.setOnClickListener(
view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
headerPopupButton.setOnClickListener(
view -> NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
headerBackgroundButton.setOnClickListener(
view -> NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
}
private PlayQueue getPlayQueue() {
return getPlayQueue(0);
}
private PlayQueue getPlayQueue(final int index) {
final List<StreamInfoItem> streamItems = new ArrayList<>();
for(InfoItem i : infoListAdapter.getItemsList()) {
if(i instanceof StreamInfoItem) {
streamItems.add((StreamInfoItem) i);
}
}
return new ChannelPlayQueue(
currentInfo.getServiceId(),
currentInfo.getUrl(),
currentInfo.getNextPageUrl(),
streamItems,
index
);
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_CHANNEL, 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;
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(serviceId), url, errorId);
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setTitle(String title) {
super.setTitle(title);
headerTitleView.setText(title);
}
}

View File

@@ -0,0 +1,448 @@
package org.schabi.newpipe.fragments.list.feed;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.subscription.SubscriptionService;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import io.reactivex.Flowable;
import io.reactivex.MaybeObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {
private static final int OFF_SCREEN_ITEMS_COUNT = 3;
private static final int MIN_ITEMS_INITIAL_LOAD = 8;
private int FEED_LOAD_COUNT = MIN_ITEMS_INITIAL_LOAD;
private int subscriptionPoolSize;
private SubscriptionService subscriptionService;
private AtomicBoolean allItemsLoaded = new AtomicBoolean(false);
private HashSet<String> itemsLoaded = new HashSet<>();
private final AtomicInteger requestLoadedAtomic = new AtomicInteger();
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private Disposable subscriptionObserver;
private Subscription feedSubscriber;
/*//////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
subscriptionService = SubscriptionService.getInstance(activity);
FEED_LOAD_COUNT = howManyItemsToLoad();
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_feed, container, false);
}
@Override
public void onPause() {
super.onPause();
disposeEverything();
}
@Override
public void onResume() {
super.onResume();
if (wasLoading.get()) doInitialLoadLogic();
}
@Override
public void onDestroy() {
super.onDestroy();
disposeEverything();
subscriptionService = null;
compositeDisposable = null;
subscriptionObserver = null;
feedSubscriber = null;
}
@Override
public void onDestroyView() {
// Do not monitor for updates when user is not viewing the feed fragment.
// This is a waste of bandwidth.
disposeEverything();
super.onDestroyView();
}
/*@Override
protected RecyclerView.LayoutManager getListLayoutManager() {
boolean isPortrait = getResources().getDisplayMetrics().heightPixels > getResources().getDisplayMetrics().widthPixels;
return new GridLayoutManager(activity, isPortrait ? 1 : 2);
}*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setTitle(R.string.fragment_whats_new);
}
if(useAsFrontPage) {
supportActionBar.setDisplayShowTitleEnabled(true);
//supportActionBar.setDisplayShowTitleEnabled(false);
}
}
@Override
public void reloadContent() {
resetFragment();
super.reloadContent();
}
/*//////////////////////////////////////////////////////////////////////////
// StateSaving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void writeTo(Queue<Object> objectsToSave) {
super.writeTo(objectsToSave);
objectsToSave.add(allItemsLoaded);
objectsToSave.add(itemsLoaded);
}
@Override
@SuppressWarnings("unchecked")
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
super.readFrom(savedObjects);
allItemsLoaded = (AtomicBoolean) savedObjects.poll();
itemsLoaded = (HashSet<String>) savedObjects.poll();
}
/*//////////////////////////////////////////////////////////////////////////
// Feed Loader
//////////////////////////////////////////////////////////////////////////*/
@Override
public void startLoading(boolean forceLoad) {
if (DEBUG) Log.d(TAG, "startLoading() called with: forceLoad = [" + forceLoad + "]");
if (subscriptionObserver != null) subscriptionObserver.dispose();
if (allItemsLoaded.get()) {
if (infoListAdapter.getItemsList().size() == 0) {
showEmptyState();
} else {
showListFooter(false);
hideLoading();
}
isLoading.set(false);
return;
}
isLoading.set(true);
showLoading();
showListFooter(true);
subscriptionObserver = subscriptionService.getSubscription()
.onErrorReturnItem(Collections.<SubscriptionEntity>emptyList())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<SubscriptionEntity>>() {
@Override
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
handleResult(subscriptionEntities);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
onError(throwable);
}
});
}
@Override
public void handleResult(@android.support.annotation.NonNull List<SubscriptionEntity> result) {
super.handleResult(result);
if (result.isEmpty()) {
infoListAdapter.clearStreamItemList();
showEmptyState();
return;
}
subscriptionPoolSize = result.size();
Flowable.fromIterable(result)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getSubscriptionObserver());
}
/**
* Responsible for reacting to user pulling request and starting a request for new feed stream.
* <p>
* On initialization, it automatically requests the amount of feed needed to display
* a minimum amount required (FEED_LOAD_SIZE).
* <p>
* Upon receiving a user pull, it creates a Single Observer to fetch the ChannelInfo
* containing the feed streams.
**/
private Subscriber<SubscriptionEntity> getSubscriptionObserver() {
return new Subscriber<SubscriptionEntity>() {
@Override
public void onSubscribe(Subscription s) {
if (feedSubscriber != null) feedSubscriber.cancel();
feedSubscriber = s;
int requestSize = FEED_LOAD_COUNT - infoListAdapter.getItemsList().size();
if (wasLoading.getAndSet(false)) requestSize = FEED_LOAD_COUNT;
boolean hasToLoad = requestSize > 0;
if (hasToLoad) {
requestLoadedAtomic.set(infoListAdapter.getItemsList().size());
requestFeed(requestSize);
}
isLoading.set(hasToLoad);
}
@Override
public void onNext(SubscriptionEntity subscriptionEntity) {
if (!itemsLoaded.contains(subscriptionEntity.getServiceId() + subscriptionEntity.getUrl())) {
subscriptionService.getChannelInfo(subscriptionEntity)
.observeOn(AndroidSchedulers.mainThread())
.onErrorComplete(new Predicate<Throwable>() {
@Override
public boolean test(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
return FeedFragment.super.onError(throwable);
}
})
.subscribe(getChannelInfoObserver(subscriptionEntity.getServiceId(), subscriptionEntity.getUrl()));
} else {
requestFeed(1);
}
}
@Override
public void onError(Throwable exception) {
FeedFragment.this.onError(exception);
}
@Override
public void onComplete() {
if (DEBUG) Log.d(TAG, "getSubscriptionObserver > onComplete() called");
}
};
}
/**
* On each request, a subscription item from the updated table is transformed
* into a ChannelInfo, containing the latest streams from the channel.
* <p>
* Currently, the feed uses the first into from the list of streams.
* <p>
* If chosen feed already displayed, then we request another feed from another
* subscription, until the subscription table runs out of new items.
* <p>
* This Observer is self-contained and will dispose itself when complete. However, this
* does not obey the fragment lifecycle and may continue running in the background
* until it is complete. This is done due to RxJava2 no longer propagate errors once
* an observer is unsubscribed while the thread process is still running.
* <p>
* To solve the above issue, we can either set a global RxJava Error Handler, or
* manage exceptions case by case. This should be done if the current implementation is
* too costly when dealing with larger subscription sets.
*
* @param url + serviceId to put in {@link #allItemsLoaded} to signal that this specific entity has been loaded.
*/
private MaybeObserver<ChannelInfo> getChannelInfoObserver(final int serviceId, final String url) {
return new MaybeObserver<ChannelInfo>() {
private Disposable observer;
@Override
public void onSubscribe(Disposable d) {
observer = d;
compositeDisposable.add(d);
isLoading.set(true);
}
// Called only when response is non-empty
@Override
public void onSuccess(final ChannelInfo channelInfo) {
if (infoListAdapter == null || channelInfo.getRelatedItems().isEmpty()) {
onDone();
return;
}
final InfoItem item = channelInfo.getRelatedItems().get(0);
// Keep requesting new items if the current one already exists
boolean itemExists = doesItemExist(infoListAdapter.getItemsList(), item);
if (!itemExists) {
infoListAdapter.addInfoItem(item);
//updateSubscription(channelInfo);
} else {
requestFeed(1);
}
onDone();
}
@Override
public void onError(Throwable exception) {
showSnackBarError(exception, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(serviceId), url, 0);
requestFeed(1);
onDone();
}
// Called only when response is empty
@Override
public void onComplete() {
onDone();
}
private void onDone() {
if (observer.isDisposed()) {
return;
}
itemsLoaded.add(serviceId + url);
compositeDisposable.remove(observer);
int loaded = requestLoadedAtomic.incrementAndGet();
if (loaded >= Math.min(FEED_LOAD_COUNT, subscriptionPoolSize)) {
requestLoadedAtomic.set(0);
isLoading.set(false);
}
if (itemsLoaded.size() == subscriptionPoolSize) {
if (DEBUG) Log.d(TAG, "getChannelInfoObserver > All Items Loaded");
allItemsLoaded.set(true);
showListFooter(false);
isLoading.set(false);
hideLoading();
if (infoListAdapter.getItemsList().size() == 0) {
showEmptyState();
}
}
}
};
}
@Override
protected void loadMoreItems() {
isLoading.set(true);
delayHandler.removeCallbacksAndMessages(null);
// Add a little of a delay when requesting more items because the cache is so fast,
// that the view seems stuck to the user when he scroll to the bottom
delayHandler.postDelayed(new Runnable() {
@Override
public void run() {
requestFeed(FEED_LOAD_COUNT);
}
}, 300);
}
@Override
protected boolean hasMoreItems() {
return !allItemsLoaded.get();
}
private final Handler delayHandler = new Handler();
private void requestFeed(final int count) {
if (DEBUG) Log.d(TAG, "requestFeed() called with: count = [" + count + "], feedSubscriber = [" + feedSubscriber + "]");
if (feedSubscriber == null) return;
isLoading.set(true);
delayHandler.removeCallbacksAndMessages(null);
feedSubscriber.request(count);
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void resetFragment() {
if (DEBUG) Log.d(TAG, "resetFragment() called");
if (subscriptionObserver != null) subscriptionObserver.dispose();
if (compositeDisposable != null) compositeDisposable.clear();
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
delayHandler.removeCallbacksAndMessages(null);
requestLoadedAtomic.set(0);
allItemsLoaded.set(false);
showListFooter(false);
itemsLoaded.clear();
}
private void disposeEverything() {
if (subscriptionObserver != null) subscriptionObserver.dispose();
if (compositeDisposable != null) compositeDisposable.clear();
if (feedSubscriber != null) feedSubscriber.cancel();
delayHandler.removeCallbacksAndMessages(null);
}
private boolean doesItemExist(final List<InfoItem> items, final InfoItem item) {
for (final InfoItem existingItem : items) {
if (existingItem.getInfoType() == item.getInfoType() &&
existingItem.getServiceId() == item.getServiceId() &&
existingItem.getName().equals(item.getName()) &&
existingItem.getUrl().equals(item.getUrl())) return true;
}
return false;
}
private int howManyItemsToLoad() {
int heightPixels = getResources().getDisplayMetrics().heightPixels;
int itemHeightPixels = activity.getResources().getDimensionPixelSize(R.dimen.video_item_search_height);
int items = itemHeightPixels > 0 ? heightPixels / itemHeightPixels + OFF_SCREEN_ITEMS_COUNT : MIN_ITEMS_INITIAL_LOAD;
return Math.max(MIN_ITEMS_INITIAL_LOAD, items);
}
/*//////////////////////////////////////////////////////////////////////////
// Fragment Error Handling
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showError(String message, boolean showRetryButton) {
resetFragment();
super.showError(message, showRetryButton);
}
@Override
protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true;
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Requesting feed", errorId);
return true;
}
}

View File

@@ -0,0 +1,186 @@
package org.schabi.newpipe.fragments.list.kiosk;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.UrlIdHandler;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.NavigationHelper;
import icepick.State;
import io.reactivex.Single;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
/**
* Created by Christian Schabesberger on 23.09.17.
*
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
* KioskFragment.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 KioskFragment extends BaseListInfoFragment<KioskInfo> {
@State
protected String kioskId = "";
protected String kioskTranslatedName;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
public static KioskFragment getInstance(int serviceId)
throws ExtractionException {
return getInstance(serviceId, NewPipe.getService(serviceId)
.getKioskList()
.getDefaultKioskId());
}
public static KioskFragment getInstance(int serviceId, String kioskId)
throws ExtractionException {
KioskFragment instance = new KioskFragment();
StreamingService service = NewPipe.getService(serviceId);
UrlIdHandler kioskTypeUrlIdHandler = service.getKioskList()
.getUrlIdHandlerByType(kioskId);
instance.setInitialData(serviceId,
kioskTypeUrlIdHandler.getUrl(kioskId),
kioskId);
instance.kioskId = kioskId;
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
kioskTranslatedName = KioskTranslator.getTranslatedKioskName(kioskId, activity);
name = kioskTranslatedName;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(useAsFrontPage && isVisibleToUser && activity != null) {
try {
setTitle(kioskTranslatedName);
} catch (Exception e) {
onUnrecoverableError(e, UserAction.UI_ERROR,
"none",
"none", R.string.app_ui_crash);
}
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_kiosk, container, false);
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null && useAsFrontPage) {
supportActionBar.setDisplayHomeAsUpEnabled(false);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
public Single<KioskInfo> loadResult(boolean forceReload) {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getKioskInfo(serviceId, url, contentCountry, forceReload);
}
@Override
public Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextPageUrl, contentCountry);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
animateView(itemsList, false, 100);
}
@Override
public void handleResult(@NonNull final KioskInfo result) {
super.handleResult(result);
name = kioskTranslatedName;
setTitle(kioskTranslatedName);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(),
UserAction.REQUESTED_KIOSK,
NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(),
UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
, "Get next page of: " + url, 0);
}
}
}

View File

@@ -0,0 +1,420 @@
package org.schabi.newpipe.fragments.list.playlist;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.fragments.local.RemotePlaylistManager;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.disposables.Disposables;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private CompositeDisposable disposables;
private Subscription bookmarkReactor;
private AtomicBoolean isBookmarkButtonReady;
private RemotePlaylistManager remotePlaylistManager;
private PlaylistRemoteEntity playlistEntity;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private TextView headerTitleView;
private View headerUploaderLayout;
private TextView headerUploaderName;
private ImageView headerUploaderAvatar;
private TextView headerStreamCount;
private View playlistCtrl;
private View headerPlayAllButton;
private View headerPopupButton;
private View headerBackgroundButton;
private MenuItem playlistBookmarkButton;
public static PlaylistFragment getInstance(int serviceId, String url, String name) {
PlaylistFragment instance = new PlaylistFragment();
instance.setInitialData(serviceId, url, name);
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
disposables = new CompositeDisposable();
isBookmarkButtonReady = new AtomicBoolean(false);
remotePlaylistManager = new RemotePlaylistManager(NewPipeDatabase.getInstance(getContext()));
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_playlist, container, false);
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
protected View getListHeader() {
headerRootLayout = activity.getLayoutInflater().inflate(R.layout.playlist_header, itemsList, false);
headerTitleView = headerRootLayout.findViewById(R.id.playlist_title_view);
headerUploaderLayout = headerRootLayout.findViewById(R.id.uploader_layout);
headerUploaderName = headerRootLayout.findViewById(R.id.uploader_name);
headerUploaderAvatar = headerRootLayout.findViewById(R.id.uploader_avatar_view);
headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count);
playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control);
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
return headerRootLayout;
}
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
infoListAdapter.useMiniItemVariants(true);
}
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup),
context.getResources().getString(R.string.start_here_on_main),
context.getResources().getString(R.string.start_here_on_background),
context.getResources().getString(R.string.start_here_on_popup),
};
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
break;
case 3:
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break;
default:
break;
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu +
"], inflater = [" + inflater + "]");
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_playlist, menu);
playlistBookmarkButton = menu.findItem(R.id.menu_item_bookmark);
updateBookmarkButtons();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (isBookmarkButtonReady != null) isBookmarkButtonReady.set(false);
if (disposables != null) disposables.clear();
if (bookmarkReactor != null) bookmarkReactor.cancel();
bookmarkReactor = null;
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposables != null) disposables.dispose();
disposables = null;
remotePlaylistManager = null;
playlistEntity = null;
isBookmarkButtonReady = null;
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
return ExtractorHelper.getMorePlaylistItems(serviceId, url, currentNextPageUrl);
}
@Override
protected Single<PlaylistInfo> loadResult(boolean forceLoad) {
return ExtractorHelper.getPlaylistInfo(serviceId, url, forceLoad);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_openInBrowser:
openUrlInBrowser(url);
break;
case R.id.menu_item_share:
shareUrl(name, url);
break;
case R.id.menu_item_bookmark:
onBookmarkClicked();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
animateView(headerRootLayout, false, 200);
animateView(itemsList, false, 100);
imageLoader.cancelDisplayTask(headerUploaderAvatar);
animateView(headerUploaderLayout, false, 200);
}
@Override
public void handleResult(@NonNull final PlaylistInfo result) {
super.handleResult(result);
animateView(headerRootLayout, true, 100);
animateView(headerUploaderLayout, true, 300);
headerUploaderLayout.setOnClickListener(null);
if (!TextUtils.isEmpty(result.getUploaderName())) {
headerUploaderName.setText(result.getUploaderName());
if (!TextUtils.isEmpty(result.getUploaderUrl())) {
headerUploaderLayout.setOnClickListener(v ->
NavigationHelper.openChannelFragment(getFragmentManager(),
result.getServiceId(), result.getUploaderUrl(),
result.getUploaderName())
);
}
}
playlistCtrl.setVisibility(View.VISIBLE);
imageLoader.displayImage(result.getUploaderAvatarUrl(), headerUploaderAvatar,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
headerStreamCount.setText(getResources().getQuantityString(R.plurals.videos,
(int) result.getStreamCount(), (int) result.getStreamCount()));
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
remotePlaylistManager.getPlaylist(result)
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getPlaylistBookmarkSubscriber());
remotePlaylistManager.onUpdate(result)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(integer -> {/* Do nothing*/}, this::onError);
headerPlayAllButton.setOnClickListener(view ->
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
headerPopupButton.setOnClickListener(view ->
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
headerBackgroundButton.setOnClickListener(view ->
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
}
private PlayQueue getPlayQueue() {
return getPlayQueue(0);
}
private PlayQueue getPlayQueue(final int index) {
final List<StreamInfoItem> infoItems = new ArrayList<>();
for(InfoItem i : infoListAdapter.getItemsList()) {
if(i instanceof StreamInfoItem) {
infoItems.add((StreamInfoItem) i);
}
}
return new PlaylistPlayQueue(
currentInfo.getServiceId(),
currentInfo.getUrl(),
currentInfo.getNextPageUrl(),
infoItems,
index
);
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
, "Get next page of: " + url, 0);
}
}
/*//////////////////////////////////////////////////////////////////////////
// OnError
//////////////////////////////////////////////////////////////////////////*/
@Override
protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true;
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
onUnrecoverableError(exception, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId), url, errorId);
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private Subscriber<List<PlaylistRemoteEntity>> getPlaylistBookmarkSubscriber() {
return new Subscriber<List<PlaylistRemoteEntity>>() {
@Override
public void onSubscribe(Subscription s) {
if (bookmarkReactor != null) bookmarkReactor.cancel();
bookmarkReactor = s;
bookmarkReactor.request(1);
}
@Override
public void onNext(List<PlaylistRemoteEntity> playlist) {
playlistEntity = playlist.isEmpty() ? null : playlist.get(0);
updateBookmarkButtons();
isBookmarkButtonReady.set(true);
if (bookmarkReactor != null) bookmarkReactor.request(1);
}
@Override
public void onError(Throwable t) {
PlaylistFragment.this.onError(t);
}
@Override
public void onComplete() {
}
};
}
@Override
public void setTitle(String title) {
super.setTitle(title);
headerTitleView.setText(title);
}
private void onBookmarkClicked() {
if (isBookmarkButtonReady == null || !isBookmarkButtonReady.get() ||
remotePlaylistManager == null)
return;
final Disposable action;
if (currentInfo != null && playlistEntity == null) {
action = remotePlaylistManager.onBookmark(currentInfo)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ignored -> {/* Do nothing */}, this::onError);
} else if (playlistEntity != null) {
action = remotePlaylistManager.deletePlaylist(playlistEntity.getUid())
.observeOn(AndroidSchedulers.mainThread())
.doFinally(() -> playlistEntity = null)
.subscribe(ignored -> {/* Do nothing */}, this::onError);
} else {
action = Disposables.empty();
}
disposables.add(action);
}
private void updateBookmarkButtons() {
if (playlistBookmarkButton == null || activity == null) return;
final int iconAttr = playlistEntity == null ?
R.attr.ic_playlist_add : R.attr.ic_playlist_check;
final int titleRes = playlistEntity == null ?
R.string.bookmark_playlist : R.string.unbookmark_playlist;
playlistBookmarkButton.setIcon(ThemeHelper.resolveResourceIdFromAttr(activity, iconAttr));
playlistBookmarkButton.setTitle(titleRes);
}
}

View File

@@ -0,0 +1,848 @@
package org.schabi.newpipe.fragments.list.search;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.TooltipCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.history.HistoryRecordManager;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.LayoutManagerSmoothScroller;
import org.schabi.newpipe.util.NavigationHelper;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import icepick.State;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class SearchFragment
extends BaseListFragment<SearchResult, ListExtractor.InfoItemsPage>
implements BackPressable {
/*//////////////////////////////////////////////////////////////////////////
// Search
//////////////////////////////////////////////////////////////////////////*/
/**
* The suggestions will only be fetched from network if the query meet this threshold (>=).
* (local ones will be fetched regardless of the length)
*/
private static final int THRESHOLD_NETWORK_SUGGESTION = 1;
/**
* How much time have to pass without emitting a item (i.e. the user stop typing) to fetch/show the suggestions, in milliseconds.
*/
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
@State
protected int filterItemCheckedId = -1;
private SearchEngine.Filter filter = SearchEngine.Filter.ANY;
@State
protected int serviceId = Constants.NO_SERVICE_ID;
@State
protected String searchQuery;
@State
protected String lastSearchedQuery;
@State
protected boolean wasSearchFocused = false;
private int currentPage = 0;
private int currentNextPage = 0;
private String contentCountry;
private boolean isSuggestionsEnabled = true;
private boolean isSearchHistoryEnabled = true;
private PublishSubject<String> suggestionPublisher = PublishSubject.create();
private Disposable searchDisposable;
private Disposable suggestionDisposable;
private CompositeDisposable disposables = new CompositeDisposable();
private SuggestionListAdapter suggestionListAdapter;
private HistoryRecordManager historyRecordManager;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View searchToolbarContainer;
private EditText searchEditText;
private View searchClear;
private View suggestionsPanel;
private RecyclerView suggestionsRecyclerView;
/*////////////////////////////////////////////////////////////////////////*/
public static SearchFragment getInstance(int serviceId, String query) {
SearchFragment searchFragment = new SearchFragment();
searchFragment.setQuery(serviceId, query);
if (!TextUtils.isEmpty(query)) {
searchFragment.setSearchOnResume();
}
return searchFragment;
}
/**
* Set wasLoading to true so when the fragment onResume is called, the initial search is done.
*/
private void setSearchOnResume() {
wasLoading.set(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Fragment's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
suggestionListAdapter = new SuggestionListAdapter(activity);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
historyRecordManager = new HistoryRecordManager(context);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
isSuggestionsEnabled = preferences.getBoolean(getString(R.string.show_search_suggestions_key), true);
contentCountry = preferences.getString(getString(R.string.content_country_key), getString(R.string.default_country_value));
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_search, container, false);
}
@Override
public void onViewCreated(View rootView, Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
showSearchOnStart();
initSearchListeners();
}
@Override
public void onPause() {
super.onPause();
wasSearchFocused = searchEditText.hasFocus();
if (searchDisposable != null) searchDisposable.dispose();
if (suggestionDisposable != null) suggestionDisposable.dispose();
if (disposables != null) disposables.clear();
hideKeyboardSearch();
}
@Override
public void onResume() {
if (DEBUG) Log.d(TAG, "onResume() called");
super.onResume();
if (!TextUtils.isEmpty(searchQuery)) {
if (wasLoading.getAndSet(false)) {
if (currentNextPage > currentPage) loadMoreItems();
else search(searchQuery);
} else if (infoListAdapter.getItemsList().size() == 0) {
if (savedState == null) {
search(searchQuery);
} else if (!isLoading.get() && !wasSearchFocused) {
infoListAdapter.clearStreamItemList();
showEmptyState();
}
}
}
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) initSuggestionObserver();
if (TextUtils.isEmpty(searchQuery) || wasSearchFocused) {
showKeyboardSearch();
showSuggestionsPanel();
} else {
hideKeyboardSearch();
hideSuggestionsPanel();
}
wasSearchFocused = false;
}
@Override
public void onDestroyView() {
if (DEBUG) Log.d(TAG, "onDestroyView() called");
unsetSearchListeners();
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
if (searchDisposable != null) searchDisposable.dispose();
if (suggestionDisposable != null) suggestionDisposable.dispose();
if (disposables != null) disposables.clear();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case ReCaptchaActivity.RECAPTCHA_REQUEST:
if (resultCode == Activity.RESULT_OK && !TextUtils.isEmpty(searchQuery)) {
search(searchQuery);
} else Log.e(TAG, "ReCaptcha failed");
break;
default:
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
break;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
suggestionsPanel = rootView.findViewById(R.id.suggestions_panel);
suggestionsRecyclerView = rootView.findViewById(R.id.suggestions_list);
suggestionsRecyclerView.setAdapter(suggestionListAdapter);
suggestionsRecyclerView.setLayoutManager(new LayoutManagerSmoothScroller(activity));
searchToolbarContainer = activity.findViewById(R.id.toolbar_search_container);
searchEditText = searchToolbarContainer.findViewById(R.id.toolbar_search_edit_text);
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void writeTo(Queue<Object> objectsToSave) {
super.writeTo(objectsToSave);
objectsToSave.add(currentPage);
objectsToSave.add(currentNextPage);
}
@Override
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
super.readFrom(savedObjects);
currentPage = (int) savedObjects.poll();
currentNextPage = (int) savedObjects.poll();
}
@Override
public void onSaveInstanceState(Bundle bundle) {
searchQuery = searchEditText != null ? searchEditText.getText().toString() : searchQuery;
super.onSaveInstanceState(bundle);
}
/*//////////////////////////////////////////////////////////////////////////
// Init's
//////////////////////////////////////////////////////////////////////////*/
@Override
public void reloadContent() {
if (!TextUtils.isEmpty(searchQuery) || (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
search(!TextUtils.isEmpty(searchQuery) ? searchQuery : searchEditText.getText().toString());
} else {
if (searchEditText != null) {
searchEditText.setText("");
showKeyboardSearch();
}
animateView(errorPanelRoot, false, 200);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
ActionBar supportActionBar = activity.getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setDisplayShowTitleEnabled(false);
supportActionBar.setDisplayHomeAsUpEnabled(true);
}
inflater.inflate(R.menu.menu_search, menu);
restoreFilterChecked(menu, filterItemCheckedId);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_filter_all:
case R.id.menu_filter_video:
case R.id.menu_filter_channel:
case R.id.menu_filter_playlist:
changeFilter(item, getFilterFromMenuId(item.getItemId()));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void restoreFilterChecked(Menu menu, int itemId) {
if (itemId != -1) {
MenuItem item = menu.findItem(itemId);
if (item == null) return;
item.setChecked(true);
filter = getFilterFromMenuId(itemId);
}
}
private SearchEngine.Filter getFilterFromMenuId(int itemId) {
switch (itemId) {
case R.id.menu_filter_video:
return SearchEngine.Filter.STREAM;
case R.id.menu_filter_channel:
return SearchEngine.Filter.CHANNEL;
case R.id.menu_filter_playlist:
return SearchEngine.Filter.PLAYLIST;
case R.id.menu_filter_all:
default:
return SearchEngine.Filter.ANY;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Search
//////////////////////////////////////////////////////////////////////////*/
private TextWatcher textWatcher;
private void showSearchOnStart() {
if (DEBUG) Log.d(TAG, "showSearchOnStart() called, searchQuery → " + searchQuery+", lastSearchedQuery → " + lastSearchedQuery);
searchEditText.setText(searchQuery);
if (TextUtils.isEmpty(searchQuery) || TextUtils.isEmpty(searchEditText.getText())) {
searchToolbarContainer.setTranslationX(100);
searchToolbarContainer.setAlpha(0f);
searchToolbarContainer.setVisibility(View.VISIBLE);
searchToolbarContainer.animate().translationX(0).alpha(1f).setDuration(200).setInterpolator(new DecelerateInterpolator()).start();
} else {
searchToolbarContainer.setTranslationX(0);
searchToolbarContainer.setAlpha(1f);
searchToolbarContainer.setVisibility(View.VISIBLE);
}
}
private void initSearchListeners() {
if (DEBUG) Log.d(TAG, "initSearchListeners() called");
searchClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
if (TextUtils.isEmpty(searchEditText.getText())) {
NavigationHelper.gotoMainFragment(getFragmentManager());
return;
}
searchEditText.setText("");
suggestionListAdapter.setItems(new ArrayList<SuggestionItem>());
showKeyboardSearch();
}
});
TooltipCompat.setTooltipText(searchClear, getString(R.string.clear));
searchEditText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) {
showSuggestionsPanel();
}
}
});
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (DEBUG) Log.d(TAG, "onFocusChange() called with: v = [" + v + "], hasFocus = [" + hasFocus + "]");
if (isSuggestionsEnabled && hasFocus && errorPanelRoot.getVisibility() != View.VISIBLE) {
showSuggestionsPanel();
}
}
});
suggestionListAdapter.setListener(new SuggestionListAdapter.OnSuggestionItemSelected() {
@Override
public void onSuggestionItemSelected(SuggestionItem item) {
search(item.query);
searchEditText.setText(item.query);
}
@Override
public void onSuggestionItemInserted(SuggestionItem item) {
searchEditText.setText(item.query);
searchEditText.setSelection(searchEditText.getText().length());
}
@Override
public void onSuggestionItemLongClick(SuggestionItem item) {
if (item.fromHistory) showDeleteSuggestionDialog(item);
}
});
if (textWatcher != null) searchEditText.removeTextChangedListener(textWatcher);
textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String newText = searchEditText.getText().toString();
suggestionPublisher.onNext(newText);
}
};
searchEditText.addTextChangedListener(textWatcher);
searchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (DEBUG) {
Log.d(TAG, "onEditorAction() called with: v = [" + v + "], actionId = [" + actionId + "], event = [" + event + "]");
}
if (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
search(searchEditText.getText().toString());
return true;
}
return false;
}
});
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) initSuggestionObserver();
}
private void unsetSearchListeners() {
if (DEBUG) Log.d(TAG, "unsetSearchListeners() called");
searchClear.setOnClickListener(null);
searchClear.setOnLongClickListener(null);
searchEditText.setOnClickListener(null);
searchEditText.setOnFocusChangeListener(null);
searchEditText.setOnEditorActionListener(null);
if (textWatcher != null) searchEditText.removeTextChangedListener(textWatcher);
textWatcher = null;
}
private void showSuggestionsPanel() {
if (DEBUG) Log.d(TAG, "showSuggestionsPanel() called");
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, true, 200);
}
private void hideSuggestionsPanel() {
if (DEBUG) Log.d(TAG, "hideSuggestionsPanel() called");
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, false, 200);
}
private void showKeyboardSearch() {
if (DEBUG) Log.d(TAG, "showKeyboardSearch() called");
if (searchEditText == null) return;
if (searchEditText.requestFocus()) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT);
}
}
private void hideKeyboardSearch() {
if (DEBUG) Log.d(TAG, "hideKeyboardSearch() called");
if (searchEditText == null) return;
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
searchEditText.clearFocus();
}
private void showDeleteSuggestionDialog(final SuggestionItem item) {
if (activity == null || historyRecordManager == null || suggestionPublisher == null ||
searchEditText == null || disposables == null) return;
final String query = item.query;
new AlertDialog.Builder(activity)
.setTitle(query)
.setMessage(R.string.delete_item_search_history)
.setCancelable(true)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.delete, (dialog, which) -> {
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
howManyDeleted -> suggestionPublisher
.onNext(searchEditText.getText().toString()),
throwable -> showSnackBarError(throwable,
UserAction.SOMETHING_ELSE, "none",
"Deleting item failed", R.string.general_error)
);
disposables.add(onDelete);
})
.show();
}
@Override
public boolean onBackPressed() {
if (suggestionsPanel.getVisibility() == View.VISIBLE && infoListAdapter.getItemsList().size() > 0 && !isLoading.get()) {
hideSuggestionsPanel();
hideKeyboardSearch();
searchEditText.setText(lastSearchedQuery);
return true;
}
return false;
}
public void giveSearchEditTextFocus() {
showKeyboardSearch();
}
private void initSuggestionObserver() {
if (DEBUG) Log.d(TAG, "initSuggestionObserver() called");
if (suggestionDisposable != null) suggestionDisposable.dispose();
final Observable<String> observable = suggestionPublisher
.debounce(SUGGESTIONS_DEBOUNCE, TimeUnit.MILLISECONDS)
.startWith(searchQuery != null ? searchQuery : "")
.filter(query -> isSuggestionsEnabled);
suggestionDisposable = observable
.switchMap(query -> {
final Flowable<List<SearchHistoryEntry>> flowable = historyRecordManager
.getRelatedSearches(query, 3, 25);
final Observable<List<SuggestionItem>> local = flowable.toObservable()
.map(searchHistoryEntries -> {
List<SuggestionItem> result = new ArrayList<>();
for (SearchHistoryEntry entry : searchHistoryEntries)
result.add(new SuggestionItem(true, entry.getSearch()));
return result;
});
if (query.length() < THRESHOLD_NETWORK_SUGGESTION) {
// Only pass through if the query length is equal or greater than THRESHOLD_NETWORK_SUGGESTION
return local.materialize();
}
final Observable<List<SuggestionItem>> network = ExtractorHelper
.suggestionsFor(serviceId, query, contentCountry)
.toObservable()
.map(strings -> {
List<SuggestionItem> result = new ArrayList<>();
for (String entry : strings) {
result.add(new SuggestionItem(false, entry));
}
return result;
});
return Observable.zip(local, network, (localResult, networkResult) -> {
List<SuggestionItem> result = new ArrayList<>();
if (localResult.size() > 0) result.addAll(localResult);
// Remove duplicates
final Iterator<SuggestionItem> iterator = networkResult.iterator();
while (iterator.hasNext() && localResult.size() > 0) {
final SuggestionItem next = iterator.next();
for (SuggestionItem item : localResult) {
if (item.query.equals(next.query)) {
iterator.remove();
break;
}
}
}
if (networkResult.size() > 0) result.addAll(networkResult);
return result;
}).materialize();
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(listNotification -> {
if (listNotification.isOnNext()) {
handleSuggestions(listNotification.getValue());
} else if (listNotification.isOnError()) {
Throwable error = listNotification.getError();
if (!ExtractorHelper.hasAssignableCauseThrowable(error,
IOException.class, SocketException.class,
InterruptedException.class, InterruptedIOException.class)) {
onSuggestionError(error);
}
}
});
}
@Override
protected void doInitialLoadLogic() {
// no-op
}
private void search(final String query) {
if (DEBUG) Log.d(TAG, "search() called with: query = [" + query + "]");
if (query.isEmpty()) return;
try {
final StreamingService service = NewPipe.getServiceByUrl(query);
if (service != null) {
showLoading();
disposables.add(Observable
.fromCallable(new Callable<Intent>() {
@Override
public Intent call() throws Exception {
return NavigationHelper.getIntentByLink(activity, service, query);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Intent>() {
@Override
public void accept(Intent intent) throws Exception {
getFragmentManager().popBackStackImmediate();
activity.startActivity(intent);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
showError(getString(R.string.url_not_supported_toast), false);
}
}));
return;
}
} catch (Exception e) {
// Exception occurred, it's not a url
}
lastSearchedQuery = query;
searchQuery = query;
currentPage = 0;
infoListAdapter.clearStreamItemList();
hideSuggestionsPanel();
hideKeyboardSearch();
historyRecordManager.onSearched(serviceId, query)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {},
error -> showSnackBarError(error, UserAction.SEARCHED,
NewPipe.getNameOfService(serviceId), query, 0)
);
suggestionPublisher.onNext(query);
startLoading(false);
}
@Override
public void startLoading(boolean forceLoad) {
super.startLoading(forceLoad);
if (disposables != null) disposables.clear();
if (searchDisposable != null) searchDisposable.dispose();
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, contentCountry, filter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
.subscribe(this::handleResult, this::onError);
}
@Override
protected void loadMoreItems() {
isLoading.set(true);
showListFooter(true);
if (searchDisposable != null) searchDisposable.dispose();
currentNextPage = currentPage + 1;
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, contentCountry, filter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
.subscribe(this::handleNextItems, this::onError);
}
@Override
protected boolean hasMoreItems() {
// TODO: No way to tell if search has more items in the moment
return true;
}
@Override
protected void onItemSelected(InfoItem selectedItem) {
super.onItemSelected(selectedItem);
hideKeyboardSearch();
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void changeFilter(MenuItem item, SearchEngine.Filter filter) {
this.filter = filter;
this.filterItemCheckedId = item.getItemId();
item.setChecked(true);
if (!TextUtils.isEmpty(searchQuery)) {
search(searchQuery);
}
}
private void setQuery(int serviceId, String searchQuery) {
this.serviceId = serviceId;
this.searchQuery = searchQuery;
}
/*//////////////////////////////////////////////////////////////////////////
// Suggestion Results
//////////////////////////////////////////////////////////////////////////*/
public void handleSuggestions(@NonNull final List<SuggestionItem> suggestions) {
if (DEBUG) Log.d(TAG, "handleSuggestions() called with: suggestions = [" + suggestions + "]");
suggestionsRecyclerView.smoothScrollToPosition(0);
suggestionsRecyclerView.post(() -> suggestionListAdapter.setItems(suggestions));
if (errorPanelRoot.getVisibility() == View.VISIBLE) {
hideLoading();
}
}
public void onSuggestionError(Throwable exception) {
if (DEBUG) Log.d(TAG, "onSuggestionError() called with: exception = [" + exception + "]");
if (super.onError(exception)) return;
int errorId = exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS, NewPipe.getNameOfService(serviceId), searchQuery, errorId);
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void hideLoading() {
super.hideLoading();
showListFooter(false);
}
@Override
public void showError(String message, boolean showRetryButton) {
super.showError(message, showRetryButton);
hideSuggestionsPanel();
hideKeyboardSearch();
}
/*//////////////////////////////////////////////////////////////////////////
// Search Results
//////////////////////////////////////////////////////////////////////////*/
@Override
public void handleResult(@NonNull SearchResult result) {
if (!result.errors.isEmpty()) {
showSnackBarError(result.errors, UserAction.SEARCHED, NewPipe.getNameOfService(serviceId), searchQuery, 0);
}
lastSearchedQuery = searchQuery;
if (infoListAdapter.getItemsList().size() == 0) {
if (!result.getResults().isEmpty()) {
infoListAdapter.addInfoItemList(result.getResults());
} else {
infoListAdapter.clearStreamItemList();
showEmptyState();
return;
}
}
super.handleResult(result);
}
@Override
public void handleNextItems(ListExtractor.InfoItemsPage result) {
showListFooter(false);
currentPage = Integer.parseInt(result.getNextPageUrl());
infoListAdapter.addInfoItemList(result.getItems());
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.SEARCHED, NewPipe.getNameOfService(serviceId)
, "\"" + searchQuery + "\" → page " + currentPage, 0);
}
super.handleNextItems(result);
}
@Override
protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true;
if (exception instanceof SearchEngine.NothingFoundException) {
infoListAdapter.clearStreamItemList();
showEmptyState();
} else {
int errorId = exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
onUnrecoverableError(exception, UserAction.SEARCHED, NewPipe.getNameOfService(serviceId), searchQuery, errorId);
}
return true;
}
}

View File

@@ -0,0 +1,16 @@
package org.schabi.newpipe.fragments.list.search;
public class SuggestionItem {
public final boolean fromHistory;
public final String query;
public SuggestionItem(boolean fromHistory, String query) {
this.fromHistory = fromHistory;
this.query = query;
}
@Override
public String toString() {
return "[" + fromHistory + "" + query + "]";
}
}

View File

@@ -0,0 +1,134 @@
package org.schabi.newpipe.fragments.list.search;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.AttrRes;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.schabi.newpipe.R;
import java.util.ArrayList;
import java.util.List;
public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAdapter.SuggestionItemHolder> {
private final ArrayList<SuggestionItem> items = new ArrayList<>();
private final Context context;
private OnSuggestionItemSelected listener;
private boolean showSuggestionHistory = true;
public interface OnSuggestionItemSelected {
void onSuggestionItemSelected(SuggestionItem item);
void onSuggestionItemInserted(SuggestionItem item);
void onSuggestionItemLongClick(SuggestionItem item);
}
public SuggestionListAdapter(Context context) {
this.context = context;
}
public void setItems(List<SuggestionItem> items) {
this.items.clear();
if (showSuggestionHistory) {
this.items.addAll(items);
} else {
// remove history items if history is disabled
for (SuggestionItem item : items) {
if (!item.fromHistory) {
this.items.add(item);
}
}
}
notifyDataSetChanged();
}
public void setListener(OnSuggestionItemSelected listener) {
this.listener = listener;
}
public void setShowSuggestionHistory(boolean v) {
showSuggestionHistory = v;
}
@Override
public SuggestionItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new SuggestionItemHolder(LayoutInflater.from(context).inflate(R.layout.item_search_suggestion, parent, false));
}
@Override
public void onBindViewHolder(SuggestionItemHolder holder, int position) {
final SuggestionItem currentItem = getItem(position);
holder.updateFrom(currentItem);
holder.queryView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) listener.onSuggestionItemSelected(currentItem);
}
});
holder.queryView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (listener != null) listener.onSuggestionItemLongClick(currentItem);
return true;
}
});
holder.insertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) listener.onSuggestionItemInserted(currentItem);
}
});
}
private SuggestionItem getItem(int position) {
return items.get(position);
}
@Override
public int getItemCount() {
return items.size();
}
public boolean isEmpty() {
return getItemCount() == 0;
}
public static class SuggestionItemHolder extends RecyclerView.ViewHolder {
private final TextView itemSuggestionQuery;
private final ImageView suggestionIcon;
private final View queryView;
private final View insertView;
// Cache some ids, as they can potentially be constantly updated/recycled
private final int historyResId;
private final int searchResId;
private SuggestionItemHolder(View rootView) {
super(rootView);
suggestionIcon = rootView.findViewById(R.id.item_suggestion_icon);
itemSuggestionQuery = rootView.findViewById(R.id.item_suggestion_query);
queryView = rootView.findViewById(R.id.suggestion_search);
insertView = rootView.findViewById(R.id.suggestion_insert);
historyResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.history);
searchResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.search);
}
private void updateFrom(SuggestionItem item) {
suggestionIcon.setImageResource(item.fromHistory ? historyResId : searchResId);
itemSuggestionQuery.setText(item.query);
}
private static int resolveResourceIdFromAttr(Context context, @AttrRes int attr) {
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
int attributeResourceId = a.getResourceId(0, 0);
a.recycle();
return attributeResourceId;
}
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.fragments.local;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class HeaderFooterHolder extends RecyclerView.ViewHolder {
public View view;
public HeaderFooterHolder(View v) {
super(v);
view = v;
}
}

View File

@@ -0,0 +1,60 @@
package org.schabi.newpipe.fragments.local;
import android.content.Context;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.util.OnClickGesture;
/*
* Created by Christian Schabesberger on 26.09.16.
* <p>
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* InfoItemBuilder.java is part of NewPipe.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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 LocalItemBuilder {
private static final String TAG = LocalItemBuilder.class.toString();
private final Context context;
private ImageLoader imageLoader = ImageLoader.getInstance();
private OnClickGesture<LocalItem> onSelectedListener;
public LocalItemBuilder(Context context) {
this.context = context;
}
public Context getContext() {
return context;
}
public void displayImage(final String url, final ImageView view,
final DisplayImageOptions options) {
imageLoader.displayImage(url, view, options);
}
public OnClickGesture<LocalItem> getOnItemSelectedListener() {
return onSelectedListener;
}
public void setOnItemSelectedListener(OnClickGesture<LocalItem> listener) {
this.onSelectedListener = listener;
}
}

View File

@@ -0,0 +1,247 @@
package org.schabi.newpipe.fragments.local;
import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.fragments.local.holder.LocalItemHolder;
import org.schabi.newpipe.fragments.local.holder.LocalPlaylistItemHolder;
import org.schabi.newpipe.fragments.local.holder.LocalPlaylistStreamItemHolder;
import org.schabi.newpipe.fragments.local.holder.LocalStatisticStreamItemHolder;
import org.schabi.newpipe.fragments.local.holder.RemotePlaylistItemHolder;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.OnClickGesture;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
/*
* Created by Christian Schabesberger on 01.08.16.
*
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* InfoListAdapter.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 LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = LocalItemListAdapter.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int HEADER_TYPE = 0;
private static final int FOOTER_TYPE = 1;
private static final int STREAM_STATISTICS_HOLDER_TYPE = 0x1000;
private static final int STREAM_PLAYLIST_HOLDER_TYPE = 0x1001;
private static final int LOCAL_PLAYLIST_HOLDER_TYPE = 0x2000;
private static final int REMOTE_PLAYLIST_HOLDER_TYPE = 0x2001;
private final LocalItemBuilder localItemBuilder;
private final ArrayList<LocalItem> localItems;
private final DateFormat dateFormat;
private boolean showFooter = false;
private View header = null;
private View footer = null;
public LocalItemListAdapter(Activity activity) {
localItemBuilder = new LocalItemBuilder(activity);
localItems = new ArrayList<>();
dateFormat = DateFormat.getDateInstance(DateFormat.SHORT,
Localization.getPreferredLocale(activity));
}
public void setSelectedListener(OnClickGesture<LocalItem> listener) {
localItemBuilder.setOnItemSelectedListener(listener);
}
public void unsetSelectedListener() {
localItemBuilder.setOnItemSelectedListener(null);
}
public void addItems(List<? extends LocalItem> data) {
if (data != null) {
if (DEBUG) {
Log.d(TAG, "addItems() before > localItems.size() = " +
localItems.size() + ", data.size() = " + data.size());
}
int offsetStart = sizeConsideringHeader();
localItems.addAll(data);
if (DEBUG) {
Log.d(TAG, "addItems() after > offsetStart = " + offsetStart +
", localItems.size() = " + localItems.size() +
", header = " + header + ", footer = " + footer +
", showFooter = " + showFooter);
}
notifyItemRangeInserted(offsetStart, data.size());
if (footer != null && showFooter) {
int footerNow = sizeConsideringHeader();
notifyItemMoved(offsetStart, footerNow);
if (DEBUG) Log.d(TAG, "addItems() footer from " + offsetStart +
" to " + footerNow);
}
}
}
public void removeItem(final LocalItem data) {
final int index = localItems.indexOf(data);
localItems.remove(index);
notifyItemRemoved(index + (header != null ? 1 : 0));
}
public boolean swapItems(int fromAdapterPosition, int toAdapterPosition) {
final int actualFrom = adapterOffsetWithoutHeader(fromAdapterPosition);
final int actualTo = adapterOffsetWithoutHeader(toAdapterPosition);
if (actualFrom < 0 || actualTo < 0) return false;
if (actualFrom >= localItems.size() || actualTo >= localItems.size()) return false;
localItems.add(actualTo, localItems.remove(actualFrom));
notifyItemMoved(fromAdapterPosition, toAdapterPosition);
return true;
}
public void clearStreamItemList() {
if (localItems.isEmpty()) {
return;
}
localItems.clear();
notifyDataSetChanged();
}
public void setHeader(View header) {
boolean changed = header != this.header;
this.header = header;
if (changed) notifyDataSetChanged();
}
public void setFooter(View view) {
this.footer = view;
}
public void showFooter(boolean show) {
if (DEBUG) Log.d(TAG, "showFooter() called with: show = [" + show + "]");
if (show == showFooter) return;
showFooter = show;
if (show) notifyItemInserted(sizeConsideringHeader());
else notifyItemRemoved(sizeConsideringHeader());
}
private int adapterOffsetWithoutHeader(final int offset) {
return offset - (header != null ? 1 : 0);
}
private int sizeConsideringHeader() {
return localItems.size() + (header != null ? 1 : 0);
}
public ArrayList<LocalItem> getItemsList() {
return localItems;
}
@Override
public int getItemCount() {
int count = localItems.size();
if (header != null) count++;
if (footer != null && showFooter) count++;
if (DEBUG) {
Log.d(TAG, "getItemCount() called, count = " + count +
", localItems.size() = " + localItems.size() +
", header = " + header + ", footer = " + footer +
", showFooter = " + showFooter);
}
return count;
}
@Override
public int getItemViewType(int position) {
if (DEBUG) Log.d(TAG, "getItemViewType() called with: position = [" + position + "]");
if (header != null && position == 0) {
return HEADER_TYPE;
} else if (header != null) {
position--;
}
if (footer != null && position == localItems.size() && showFooter) {
return FOOTER_TYPE;
}
final LocalItem item = localItems.get(position);
switch (item.getLocalItemType()) {
case PLAYLIST_LOCAL_ITEM: return LOCAL_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_REMOTE_ITEM: return REMOTE_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_STREAM_ITEM: return STREAM_PLAYLIST_HOLDER_TYPE;
case STATISTIC_STREAM_ITEM: return STREAM_STATISTICS_HOLDER_TYPE;
default:
Log.e(TAG, "No holder type has been considered for item: [" +
item.getLocalItemType() + "]");
return -1;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
if (DEBUG) Log.d(TAG, "onCreateViewHolder() called with: parent = [" +
parent + "], type = [" + type + "]");
switch (type) {
case HEADER_TYPE:
return new HeaderFooterHolder(header);
case FOOTER_TYPE:
return new HeaderFooterHolder(footer);
case LOCAL_PLAYLIST_HOLDER_TYPE:
return new LocalPlaylistItemHolder(localItemBuilder, parent);
case REMOTE_PLAYLIST_HOLDER_TYPE:
return new RemotePlaylistItemHolder(localItemBuilder, parent);
case STREAM_PLAYLIST_HOLDER_TYPE:
return new LocalPlaylistStreamItemHolder(localItemBuilder, parent);
case STREAM_STATISTICS_HOLDER_TYPE:
return new LocalStatisticStreamItemHolder(localItemBuilder, parent);
default:
Log.e(TAG, "No view type has been considered for holder: [" + type + "]");
return null;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (DEBUG) Log.d(TAG, "onBindViewHolder() called with: holder = [" +
holder.getClass().getSimpleName() + "], position = [" + position + "]");
if (holder instanceof LocalItemHolder) {
// If header isn't null, offset the items by -1
if (header != null) position--;
((LocalItemHolder) holder).updateFromItem(localItems.get(position), dateFormat);
} else if (holder instanceof HeaderFooterHolder && position == 0 && header != null) {
((HeaderFooterHolder) holder).view = header;
} else if (holder instanceof HeaderFooterHolder && position == sizeConsideringHeader()
&& footer != null && showFooter) {
((HeaderFooterHolder) holder).view = footer;
}
}
}

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