mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-10-04 13:40:52 +02:00
Compare commits
496 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
54c32b9fe2 | ||
![]() |
9d5951765f | ||
![]() |
ddc3b47dfa | ||
![]() |
59523d6a08 | ||
![]() |
686f395158 | ||
![]() |
f7b7340b30 | ||
![]() |
9bcdad0218 | ||
![]() |
ff4601f487 | ||
![]() |
535cebde51 | ||
![]() |
ed23faa455 | ||
![]() |
0c695d721d | ||
![]() |
d7a208dcee | ||
![]() |
3eb2a26e4e | ||
![]() |
cc2d365e5a | ||
![]() |
76ac2cc58e | ||
![]() |
aee26fcffc | ||
![]() |
685eebeb56 | ||
![]() |
f23ae091cc | ||
![]() |
1421dca35f | ||
![]() |
39c2f31a22 | ||
![]() |
239ef1c238 | ||
![]() |
466ba93750 | ||
![]() |
72007a0162 | ||
![]() |
26c0445b83 | ||
![]() |
6f6c1704d4 | ||
![]() |
14aa6de422 | ||
![]() |
eeb770ffe3 | ||
![]() |
382ac3470b | ||
![]() |
3abfb08090 | ||
![]() |
b4aac839c9 | ||
![]() |
da984c23df | ||
![]() |
cab770159d | ||
![]() |
7c2ff977d8 | ||
![]() |
5bd9334f8f | ||
![]() |
c5544df64c | ||
![]() |
c85e3c07d6 | ||
![]() |
674e1c0519 | ||
![]() |
7154a1edb8 | ||
![]() |
be1252e0e6 | ||
![]() |
a4ce6c707c | ||
![]() |
affce74b84 | ||
![]() |
730de4061f | ||
![]() |
3beafa2a74 | ||
![]() |
c622923edd | ||
![]() |
6940021293 | ||
![]() |
0156a4f39e | ||
![]() |
4bae12aa55 | ||
![]() |
f08b1224c9 | ||
![]() |
477355db8f | ||
![]() |
11c89165c5 | ||
![]() |
825f28ab9a | ||
![]() |
54ff5e1dc6 | ||
![]() |
9b46418628 | ||
![]() |
04597a9faf | ||
![]() |
5b0994dc85 | ||
![]() |
7c852c69a3 | ||
![]() |
df47e94ceb | ||
![]() |
3b68004005 | ||
![]() |
5a9c327938 | ||
![]() |
3e31e9783c | ||
![]() |
46fb3639ec | ||
![]() |
a6eba57099 | ||
![]() |
c8481f961a | ||
![]() |
56329f43fb | ||
![]() |
793fbfb5be | ||
![]() |
1d8334b762 | ||
![]() |
19330ac415 | ||
![]() |
7a015a0bda | ||
![]() |
f29c422c61 | ||
![]() |
99a369f604 | ||
![]() |
c1f0fb36ac | ||
![]() |
fa0a8905f7 | ||
![]() |
4e63a3269e | ||
![]() |
0f1873e295 | ||
![]() |
23fd28afd5 | ||
![]() |
ad5a813a9a | ||
![]() |
f245eedbdf | ||
![]() |
1ce6a6e8c5 | ||
![]() |
0ea7b5526c | ||
![]() |
b41e88f8f3 | ||
![]() |
82b9e79d99 | ||
![]() |
a5383fadb1 | ||
![]() |
bd7fb9bbe4 | ||
![]() |
1ddd0a333c | ||
![]() |
084fec08a6 | ||
![]() |
2b51448b49 | ||
![]() |
f4eee83477 | ||
![]() |
cd622c9e06 | ||
![]() |
7077ebfde2 | ||
![]() |
4862fecb12 | ||
![]() |
c189933705 | ||
![]() |
9c3f7a9139 | ||
![]() |
382bf5e936 | ||
![]() |
e2fac962f3 | ||
![]() |
3071ebc0d5 | ||
![]() |
a5fc6db1fa | ||
![]() |
8060c6a775 | ||
![]() |
2a6e7f300c | ||
![]() |
98afe79eaa | ||
![]() |
a35590f9ea | ||
![]() |
f14f8c35b8 | ||
![]() |
aa5c510c99 | ||
![]() |
59f33a8def | ||
![]() |
dbb4df598c | ||
![]() |
8452f52da0 | ||
![]() |
db6613f562 | ||
![]() |
44d2775437 | ||
![]() |
a3326dc598 | ||
![]() |
0cd56ddeb8 | ||
![]() |
2a7f729e73 | ||
![]() |
18301d8f8b | ||
![]() |
8286437055 | ||
![]() |
1bef7fbbf3 | ||
![]() |
21e8318643 | ||
![]() |
381f054daf | ||
![]() |
c05d9303a9 | ||
![]() |
cca72a9e4e | ||
![]() |
d4463e5f30 | ||
![]() |
92155e2154 | ||
![]() |
287fd0bf1e | ||
![]() |
9e910d5501 | ||
![]() |
ff54b4d0c9 | ||
![]() |
af0b841bc3 | ||
![]() |
665ea85613 | ||
![]() |
de635392c6 | ||
![]() |
7814cca3d5 | ||
![]() |
6c7204eae0 | ||
![]() |
834d647011 | ||
![]() |
d872263b55 | ||
![]() |
4f8e4ca0ad | ||
![]() |
2abc9d0210 | ||
![]() |
36fb942ce6 | ||
![]() |
56476b35e3 | ||
![]() |
38b3835891 | ||
![]() |
ccf5be116a | ||
![]() |
794ae4c5da | ||
![]() |
060e744924 | ||
![]() |
de62ed772f | ||
![]() |
6a8c4a65c5 | ||
![]() |
03738aeb27 | ||
![]() |
243cb8569e | ||
![]() |
1bd660fbbe | ||
![]() |
fec80b39f0 | ||
![]() |
21768432c8 | ||
![]() |
e9b900ff28 | ||
![]() |
c57cb8fec1 | ||
![]() |
247681e3ef | ||
![]() |
2f9142419a | ||
![]() |
b84eb3df7f | ||
![]() |
4058ec2ee9 | ||
![]() |
23a9061871 | ||
![]() |
9e95ca10b2 | ||
![]() |
4c0809d3d3 | ||
![]() |
d43365f6e6 | ||
![]() |
c6ccc2b20d | ||
![]() |
31dd68be1d | ||
![]() |
1c94620c06 | ||
![]() |
82d214faa6 | ||
![]() |
04b2e3689c | ||
![]() |
f00b8a3941 | ||
![]() |
390cc9cfc9 | ||
![]() |
8259872e2d | ||
![]() |
1a3aaf86ee | ||
![]() |
cade4f932d | ||
![]() |
eb060602cd | ||
![]() |
805f046696 | ||
![]() |
35e11e43de | ||
![]() |
ba15c6dc60 | ||
![]() |
569c227a99 | ||
![]() |
8fd7599158 | ||
![]() |
19418e5dfb | ||
![]() |
f90a163ede | ||
![]() |
8fb1fd3602 | ||
![]() |
0dbf2a347f | ||
![]() |
38742fd5e8 | ||
![]() |
67ce7e0979 | ||
![]() |
21a7e52f9a | ||
![]() |
fcb445a381 | ||
![]() |
f6450d4b4d | ||
![]() |
a01d1b89b6 | ||
![]() |
0c9b6582cc | ||
![]() |
2d47daabf8 | ||
![]() |
ce20cbe435 | ||
![]() |
99e5415bfc | ||
![]() |
b2d935dd6d | ||
![]() |
eb66cc5db8 | ||
![]() |
6d6b8363a8 | ||
![]() |
bf79b02e15 | ||
![]() |
3ce7eda3eb | ||
![]() |
378e6b6547 | ||
![]() |
f63b35e2c0 | ||
![]() |
9a480cbe3e | ||
![]() |
76ca937bb8 | ||
![]() |
8a29567572 | ||
![]() |
839cd7d1c7 | ||
![]() |
0bfc7a9177 | ||
![]() |
26e11f96e0 | ||
![]() |
86c36acedc | ||
![]() |
2318ad2bde | ||
![]() |
9548dfabd6 | ||
![]() |
0c716c12d7 | ||
![]() |
08dd176753 | ||
![]() |
07086bfb3e | ||
![]() |
b1d2e64450 | ||
![]() |
d9cd928100 | ||
![]() |
37ec26c8fd | ||
![]() |
68b7d9cdff | ||
![]() |
3aecd15916 | ||
![]() |
97d76aee18 | ||
![]() |
781bf8e7ec | ||
![]() |
77b9457707 | ||
![]() |
1210ab0de0 | ||
![]() |
3c93c4714e | ||
![]() |
f90a1ede70 | ||
![]() |
028354b283 | ||
![]() |
18493a578d | ||
![]() |
1829dc79c8 | ||
![]() |
7575e8fbe3 | ||
![]() |
eed9915c12 | ||
![]() |
be71e45954 | ||
![]() |
3a7978eca0 | ||
![]() |
c37d2250d4 | ||
![]() |
45819d1cd4 | ||
![]() |
4ac36af40c | ||
![]() |
1a2840b33f | ||
![]() |
d7e75e6011 | ||
![]() |
73316b87a3 | ||
![]() |
46402691b0 | ||
![]() |
e7cef4549f | ||
![]() |
737a41f45b | ||
![]() |
045ca40a77 | ||
![]() |
b1fe197c11 | ||
![]() |
8888530ae3 | ||
![]() |
2d51c7428e | ||
![]() |
863e2a80a2 | ||
![]() |
41d17d2a47 | ||
![]() |
36934468d6 | ||
![]() |
5029ce8728 | ||
![]() |
e6ab24bcb4 | ||
![]() |
f3bd263ada | ||
![]() |
db7ab3ffce | ||
![]() |
85c3755b96 | ||
![]() |
5decd55551 | ||
![]() |
bc468b6f36 | ||
![]() |
369d9204d9 | ||
![]() |
7caf7be97e | ||
![]() |
64c423902a | ||
![]() |
27a2dee3bd | ||
![]() |
11d3aeb0dd | ||
![]() |
f54d8d318a | ||
![]() |
210f2ef452 | ||
![]() |
d0bab6183a | ||
![]() |
3441aceba3 | ||
![]() |
0908b9cd76 | ||
![]() |
67494ad4c4 | ||
![]() |
5d8f75beb4 | ||
![]() |
8e7fde99db | ||
![]() |
bfdf165584 | ||
![]() |
9427ebd489 | ||
![]() |
e4f753ae82 | ||
![]() |
f2d9d3c2d7 | ||
![]() |
04c5f31cc1 | ||
![]() |
4ea86b714e | ||
![]() |
cc0b96cba4 | ||
![]() |
9e176f8400 | ||
![]() |
7195ff349b | ||
![]() |
8048ad343e | ||
![]() |
799a27ec84 | ||
![]() |
c7c77ab20c | ||
![]() |
8fc113cc52 | ||
![]() |
c7679bec87 | ||
![]() |
3301d8b4fb | ||
![]() |
f5892093a9 | ||
![]() |
b06238ba5d | ||
![]() |
dddcc80f30 | ||
![]() |
8854c8c9d0 | ||
![]() |
d02f441eb0 | ||
![]() |
ff89dd00b6 | ||
![]() |
7041e63268 | ||
![]() |
8126fdcd15 | ||
![]() |
2d61a2f251 | ||
![]() |
7594ee9dbe | ||
![]() |
0862a38599 | ||
![]() |
bf7dc462e8 | ||
![]() |
65b6aaec8e | ||
![]() |
e08aa14eab | ||
![]() |
851028997a | ||
![]() |
a1479d04df | ||
![]() |
d12af16f46 | ||
![]() |
2edfcb78fe | ||
![]() |
3f0947fa5b | ||
![]() |
d2b808e540 | ||
![]() |
2995a7dc8f | ||
![]() |
819db0a30b | ||
![]() |
4d727245e1 | ||
![]() |
d8281aeb34 | ||
![]() |
cd0f2061b5 | ||
![]() |
96928d46ca | ||
![]() |
6d55ac2199 | ||
![]() |
80dae6ece7 | ||
![]() |
a1a12ca9f7 | ||
![]() |
5a594173fa | ||
![]() |
1e989945b9 | ||
![]() |
679bef849c | ||
![]() |
1c17be9760 | ||
![]() |
6def0e3115 | ||
![]() |
fd3436d5c0 | ||
![]() |
a94f9fd3e5 | ||
![]() |
77850464d4 | ||
![]() |
3e9edba189 | ||
![]() |
3d168542fe | ||
![]() |
0de00e26d8 | ||
![]() |
f0705c612e | ||
![]() |
648b9b5d02 | ||
![]() |
b15a0b92f9 | ||
![]() |
80482c0578 | ||
![]() |
16701923a1 | ||
![]() |
67cee06523 | ||
![]() |
685dab39af | ||
![]() |
0ff9555cc4 | ||
![]() |
4f808dd17d | ||
![]() |
69d71dac36 | ||
![]() |
4880319991 | ||
![]() |
13b9850b39 | ||
![]() |
366f645eda | ||
![]() |
dcf7190c90 | ||
![]() |
ae6647276c | ||
![]() |
460ff37f7a | ||
![]() |
e7ef913416 | ||
![]() |
c149050a3a | ||
![]() |
a4e5ca54db | ||
![]() |
cb81fd3353 | ||
![]() |
3a8611ebf8 | ||
![]() |
352a883b5d | ||
![]() |
5247b22ef4 | ||
![]() |
1bf00e80b0 | ||
![]() |
6331d9b7a4 | ||
![]() |
0deb0ad851 | ||
![]() |
3b42041c4e | ||
![]() |
d8987aa94a | ||
![]() |
19ed16efc6 | ||
![]() |
0e32d70aef | ||
![]() |
5b71f279fd | ||
![]() |
6d170ffb16 | ||
![]() |
72d90374a0 | ||
![]() |
fc8160acda | ||
![]() |
751ffb9de9 | ||
![]() |
60d636940d | ||
![]() |
7a5cca519a | ||
![]() |
1e93d06a25 | ||
![]() |
4341f8aaec | ||
![]() |
46022d60f3 | ||
![]() |
80ddc76926 | ||
![]() |
bd999b4b0a | ||
![]() |
4cdc387338 | ||
![]() |
df258a0003 | ||
![]() |
7cc1c0fbdd | ||
![]() |
42644c956b | ||
![]() |
00eaedcbfa | ||
![]() |
1ff5a97c85 | ||
![]() |
241414f81b | ||
![]() |
1bf046a8ba | ||
![]() |
61471fdd3c | ||
![]() |
a0524fb136 | ||
![]() |
fa39389a64 | ||
![]() |
697a24e699 | ||
![]() |
cf3bb87a54 | ||
![]() |
14fb7d8a7a | ||
![]() |
d097363b24 | ||
![]() |
bad576c23d | ||
![]() |
8d9e4e7442 | ||
![]() |
431d03c63f | ||
![]() |
24321731d9 | ||
![]() |
fddcade1fb | ||
![]() |
a0aa7dcdc1 | ||
![]() |
d3e9f354b3 | ||
![]() |
e958334406 | ||
![]() |
a42029970d | ||
![]() |
2108e09e13 | ||
![]() |
8c010093e8 | ||
![]() |
adc98be441 | ||
![]() |
fb942912db | ||
![]() |
7f12b58722 | ||
![]() |
05d58f8f98 | ||
![]() |
46c2db310a | ||
![]() |
607408b9b9 | ||
![]() |
b81e8cb81a | ||
![]() |
44ef04d90a | ||
![]() |
3e9d84b109 | ||
![]() |
aa2d8d4833 | ||
![]() |
55f63b948b | ||
![]() |
cece543d6b | ||
![]() |
9204a89319 | ||
![]() |
f8ed96bb25 | ||
![]() |
54d318bf04 | ||
![]() |
f152d66cd8 | ||
![]() |
576786c751 | ||
![]() |
a6b7cd3202 | ||
![]() |
ea9caaaaf0 | ||
![]() |
22d8f434be | ||
![]() |
8360c10141 | ||
![]() |
750dc6f2cc | ||
![]() |
47b556544d | ||
![]() |
f6cee739a6 | ||
![]() |
d1afe0028c | ||
![]() |
a4cace1ef7 | ||
![]() |
707ac8be27 | ||
![]() |
2f2254966a | ||
![]() |
eb57675f55 | ||
![]() |
dde93c5ccf | ||
![]() |
886b5959f7 | ||
![]() |
dc44546ac7 | ||
![]() |
42c6698732 | ||
![]() |
bd014a107f | ||
![]() |
3a7298bb99 | ||
![]() |
aa06e3490d | ||
![]() |
ece889b36b | ||
![]() |
9848f19ce6 | ||
![]() |
e59b087057 | ||
![]() |
5b451d1ac7 | ||
![]() |
f050c05b3c | ||
![]() |
06b8edefbf | ||
![]() |
f3a2a28398 | ||
![]() |
9b0a1fc2ec | ||
![]() |
c87ab234eb | ||
![]() |
68468756a8 | ||
![]() |
9016df0195 | ||
![]() |
7acece9705 | ||
![]() |
d1896c23c0 | ||
![]() |
dae19f03e0 | ||
![]() |
9dafccf0f7 | ||
![]() |
5f270c41ae | ||
![]() |
f9f80e9003 | ||
![]() |
c5063d4269 | ||
![]() |
ccbe18ec1c | ||
![]() |
321a8a8b25 | ||
![]() |
77a9560376 | ||
![]() |
058a039a82 | ||
![]() |
7c744703e4 | ||
![]() |
a934cbb085 | ||
![]() |
cf4158c0d0 | ||
![]() |
dc56eab9b6 | ||
![]() |
37d1f59132 | ||
![]() |
ab0ce55411 | ||
![]() |
c1d66596d1 | ||
![]() |
cbfccdf0d3 | ||
![]() |
9362037177 | ||
![]() |
e25c93bae2 | ||
![]() |
367c434010 | ||
![]() |
02d8463e15 | ||
![]() |
9d5a1d5c43 | ||
![]() |
c8d94f541f | ||
![]() |
27d06eaa6b | ||
![]() |
7f32857e00 | ||
![]() |
2f060f0f52 | ||
![]() |
f89d405226 | ||
![]() |
fd4459e570 | ||
![]() |
eb0df2b101 | ||
![]() |
6c178cfb7e | ||
![]() |
8ced68430d | ||
![]() |
0aade598ff | ||
![]() |
95949fd1ab | ||
![]() |
1a56382112 | ||
![]() |
d610e4b19b | ||
![]() |
fc44d9e36e | ||
![]() |
c07686576a | ||
![]() |
c2400aea4d | ||
![]() |
fb4bf0dde4 | ||
![]() |
e4f638d1ce | ||
![]() |
5c492c01a1 | ||
![]() |
f451e11f82 | ||
![]() |
95b73f35f7 | ||
![]() |
58147e9e12 | ||
![]() |
a8830e2ede | ||
![]() |
9804bb95cc | ||
![]() |
0da1aef763 | ||
![]() |
0a334804a3 | ||
![]() |
94d2f03e9b | ||
![]() |
9127f7f0c2 | ||
![]() |
0bb0226bc2 | ||
![]() |
b3a1a5dcc2 | ||
![]() |
984dd1cc25 | ||
![]() |
5663e543a4 | ||
![]() |
d3879a0398 | ||
![]() |
6bd2468d44 | ||
![]() |
e63d43151b | ||
![]() |
0265da4ae6 | ||
![]() |
ef255d12ae | ||
![]() |
eeb612f9a2 | ||
![]() |
dfcb4edb81 | ||
![]() |
d90162d06f | ||
![]() |
97c924341c | ||
![]() |
cd3f405bff | ||
![]() |
7cfdca7a81 | ||
![]() |
216063dba8 | ||
![]() |
b647bacd72 |
@@ -20,6 +20,7 @@ android:
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
||||||
|
- GRADLE_OPTS=-Xmx512m # give gradle more memory since it seem to fail otherwise
|
||||||
matrix:
|
matrix:
|
||||||
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
|
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
|
||||||
|
|
||||||
@@ -28,3 +29,5 @@ before_script:
|
|||||||
- emulator -avd test -no-skin -no-audio -no-window &
|
- emulator -avd test -no-skin -no-audio -no-window &
|
||||||
- android-wait-for-emulator
|
- android-wait-for-emulator
|
||||||
- adb shell input keyevent 82 &
|
- adb shell input keyevent 82 &
|
||||||
|
|
||||||
|
script: ./gradlew --info build connectedCheck
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
#Contributing
|
#Contribution
|
||||||
|
|
||||||
This document contains guidelines on making contributions to NewPipe.
|
This document contains guidelines on making contributions to NewPipe.
|
||||||
|
|
||||||
## Programming
|
## Programming
|
||||||
|
|
||||||
* Follow the [Google Style Guidelines](https://google.github.io/styleguide/javaguide.html)
|
* Follow the [Google Style Guidelines](https://google.github.io/styleguide/javaguide.html)
|
||||||
* Make a new feature on a seperate branch, not on the master branch
|
* Make a new feature on a separate branch, not on the master branch
|
||||||
* Make a [pull request](https://github.com/theScrabi/NewPipe/pulls) if you're done with your changes
|
* Make a [pull request](https://github.com/theScrabi/NewPipe/pulls) if you're done with your changes
|
||||||
* When submitting changes, you agree that your code will be GPLv3 licensed
|
* When submitting changes, you agree that your code will be GPLv3 licensed
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ This document contains guidelines on making contributions to NewPipe.
|
|||||||
compatibility with all git tools
|
compatibility with all git tools
|
||||||
* [This guide](http://chris.beams.io/posts/git-commit/) goes more in depth on what makes a good commit message
|
* [This guide](http://chris.beams.io/posts/git-commit/) goes more in depth on what makes a good commit message
|
||||||
|
|
||||||
## Translating
|
## Translation
|
||||||
|
|
||||||
* NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/)
|
* NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/)
|
||||||
|
|
||||||
@@ -30,4 +30,4 @@ This document contains guidelines on making contributions to NewPipe.
|
|||||||
## Communication
|
## Communication
|
||||||
|
|
||||||
* For the time being, [Slack](http://invite.chschtsch.ml/) is being used for project communication
|
* For the time being, [Slack](http://invite.chschtsch.ml/) is being used for project communication
|
||||||
* Feel free to post suggestions, changes ideas etc!
|
* Feel free to post suggestions, changes, ideas etc!
|
||||||
|
12
README.md
12
README.md
@@ -1,7 +1,7 @@
|
|||||||
# NewPipe
|
# NewPipe
|
||||||
NewPipe: A free lightweight Youtube frontend for Android.
|
NewPipe: A free lightweight Youtube frontend for Android.
|
||||||
|
|
||||||
[](http://dasochan.nl/newpipe/)
|
[](https://newpipe.schabi.org)
|
||||||
|
|
||||||
Project status:
|
Project status:
|
||||||
[](https://hosted.weblate.org/engage/NewPipe/)
|
[](https://hosted.weblate.org/engage/NewPipe/)
|
||||||
@@ -11,6 +11,12 @@ Project status:
|
|||||||
|
|
||||||
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
||||||
|
|
||||||
|
## Donate
|
||||||
|

|
||||||
|
`16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
|
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
|
||||||
@@ -18,7 +24,6 @@ Project status:
|
|||||||
[<img src="screenshots/screenshot_3.png" width=150>](screenshots/screenshot_3.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_4.png" width=150>](screenshots/screenshot_4.png)
|
||||||
[<img src="screenshots/screenshot_5.png" width=150>](screenshots/screenshot_5.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)
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@@ -36,6 +41,8 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Open a video in Kodi
|
* Open a video in Kodi
|
||||||
* Show Next/Related videos
|
* Show Next/Related videos
|
||||||
* Search YouTube in a specific language
|
* Search YouTube in a specific language
|
||||||
|
* Orbot/Tor support (no streaming yet, experimental)
|
||||||
|
* Watch age restricted material
|
||||||
|
|
||||||
### Coming Features
|
### Coming Features
|
||||||
|
|
||||||
@@ -48,6 +55,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Subscribe to channels
|
* Subscribe to channels
|
||||||
* Watch videos from a channel
|
* Watch videos from a channel
|
||||||
* Search/Watch Playlists
|
* Search/Watch Playlists
|
||||||
|
* Queeing videos
|
||||||
* ... and many more
|
* ... and many more
|
||||||
|
|
||||||
### Multiservice support
|
### Multiservice support
|
||||||
|
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 23
|
||||||
buildToolsVersion "23.0.2"
|
buildToolsVersion '23.0.2'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 10
|
versionCode 18
|
||||||
versionName "0.7.1"
|
versionName "0.8.0"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -24,15 +24,24 @@ android {
|
|||||||
// but continue the build even when errors are found:
|
// but continue the build even when errors are found:
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_7
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_7
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile 'com.android.support:appcompat-v7:23.4.0'
|
||||||
compile 'com.android.support:appcompat-v7:23.1.1'
|
compile 'com.android.support:support-v4:23.4.0'
|
||||||
compile 'com.android.support:support-v4:23.1.1'
|
compile 'com.android.support:design:23.4.0'
|
||||||
compile 'com.android.support:design:23.1.1'
|
compile 'com.android.support:recyclerview-v7:23.4.0'
|
||||||
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.jsoup:jsoup:1.8.3'
|
||||||
compile 'org.mozilla:rhino:1.7.7'
|
compile 'org.mozilla:rhino:1.7.7'
|
||||||
|
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
||||||
|
compile 'de.hdodenhof:circleimageview:2.0.0'
|
||||||
|
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||||
|
compile 'com.github.nirhart:parallaxscroll:1.0'
|
||||||
|
compile 'com.google.android.exoplayer:exoplayer:r1.5.5'
|
||||||
|
compile 'com.google.code.gson:gson:2.4'
|
||||||
|
compile 'com.nononsenseapps:filepicker:2.0.5'
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,127 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||||
|
import org.schabi.newpipe.extractor.SearchResult;
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
||||||
|
import org.schabi.newpipe.extractor.SearchEngine;
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 29.12.15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeSearchEngineTest.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 YoutubeSearchEngineTest extends AndroidTestCase {
|
||||||
|
private SearchResult result;
|
||||||
|
private ArrayList<String> suggestionReply;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception{
|
||||||
|
super.setUp();
|
||||||
|
SearchEngine engine = ServiceList.getService("Youtube")
|
||||||
|
.getSearchEngineInstance(new Downloader());
|
||||||
|
|
||||||
|
result = engine.search("star wars",
|
||||||
|
0, "de", new Downloader()).getSearchResult();
|
||||||
|
suggestionReply = engine.suggestionList("hello","de",new Downloader());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfNoErrorOccur() {
|
||||||
|
assertTrue(result.errors.isEmpty() ? "" : getStackTrace(result.errors.get(0))
|
||||||
|
,result.errors.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfListIsNotEmpty() {
|
||||||
|
assertEquals(result.resultList.size() > 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testItemsHaveTitle() {
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertEquals(i.title.isEmpty(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testItemsHaveUploader() {
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertEquals(i.uploader.isEmpty(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testItemsHaveRightDuration() {
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue(i.duration >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testItemsHaveRightThumbnail() {
|
||||||
|
for (StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue(i.thumbnail_url, i.thumbnail_url.contains("https://"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testItemsHaveRightVideoUrl() {
|
||||||
|
for (StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue(i.webpage_url, i.webpage_url.contains("https://"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testViewCount() {
|
||||||
|
/*
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue(Long.toString(i.view_count), i.view_count != -1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// that specific link used for this test, there are no videos with less
|
||||||
|
// than 10.000 views, so we can test against that.
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue(i.title + ": " + Long.toString(i.view_count), i.view_count >= 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStreamType() {
|
||||||
|
for(StreamPreviewInfo i : result.resultList) {
|
||||||
|
assertTrue("not a livestream and not a video",
|
||||||
|
i.stream_type == AbstractVideoInfo.StreamType.VIDEO_STREAM ||
|
||||||
|
i.stream_type == AbstractVideoInfo.StreamType.LIVE_STREAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfSuggestionsAreReplied() {
|
||||||
|
assertEquals(!suggestionReply.isEmpty(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfSuggestionsAreValid() {
|
||||||
|
for(String s : suggestionReply) {
|
||||||
|
assertTrue(s, !s.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getStackTrace(final Throwable throwable) {
|
||||||
|
final StringWriter sw = new StringWriter();
|
||||||
|
final PrintWriter pw = new PrintWriter(sw, true);
|
||||||
|
throwable.printStackTrace(pw);
|
||||||
|
return sw.getBuffer().toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,113 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||||
|
import org.schabi.newpipe.extractor.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.VideoStream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 30.12.15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeVideoExtractorDefault.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 YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
|
public void setUp() throws IOException, ExtractionException {
|
||||||
|
extractor = ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=YQHsXMglC9A", new Downloader());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetInvalidTimeStamp() throws ParsingException {
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||||
|
StreamExtractor extractor =
|
||||||
|
ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174", new Downloader());
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() == 174);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetTitle() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getTitle().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDescription() throws ParsingException {
|
||||||
|
assertTrue(extractor.getDescription() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploader() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getUploader().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetLength() throws ParsingException {
|
||||||
|
assertTrue(extractor.getLength() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetViewCount() throws ParsingException {
|
||||||
|
assertTrue(Long.toString(extractor.getViewCount()),
|
||||||
|
extractor.getViewCount() > /* specific to that video */ 1224000074);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploadDate() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploadDate().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getThumbnailUrl(),
|
||||||
|
extractor.getThumbnailUrl().contains("https://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||||
|
extractor.getUploaderThumbnailUrl().contains("https://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAudioStreams() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getAudioStreams().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetVideoStreams() throws ParsingException {
|
||||||
|
for(VideoStream s : extractor.getVideoStreams()) {
|
||||||
|
assertTrue(s.url,
|
||||||
|
s.url.contains("https://"));
|
||||||
|
assertTrue(s.resolution.length() > 0);
|
||||||
|
assertTrue(Integer.toString(s.format),
|
||||||
|
0 <= s.format && s.format <= 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStreamType() throws ParsingException {
|
||||||
|
assertTrue(extractor.getStreamType() == AbstractVideoInfo.StreamType.VIDEO_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDashMpd() throws ParsingException {
|
||||||
|
assertTrue(extractor.getDashMpdUrl(),
|
||||||
|
extractor.getDashMpdUrl() != null || !extractor.getDashMpdUrl().isEmpty());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 30.12.15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeVideoExtractorGema.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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// This class only works in Germany.
|
||||||
|
public class YoutubeStreamExtractorGemaTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
// Deaktivate this Test Case bevore uploading it githup, otherwise CI will fail.
|
||||||
|
private static final boolean testActive = false;
|
||||||
|
|
||||||
|
public void testGemaError() throws IOException, ExtractionException {
|
||||||
|
if(testActive) {
|
||||||
|
try {
|
||||||
|
ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=3O1_3zBUKM8",
|
||||||
|
new Downloader());
|
||||||
|
} catch(YoutubeStreamExtractor.GemaException ge) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,87 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.VideoStream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class YoutubeStreamExtractorRestrictedTest extends AndroidTestCase {
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
|
public void setUp() throws IOException, ExtractionException {
|
||||||
|
extractor = ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=i6JTvzrpBy0",
|
||||||
|
new Downloader());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetInvalidTimeStamp() throws ParsingException {
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||||
|
StreamExtractor extractor=ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174",
|
||||||
|
new Downloader());
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() == 174);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAgeLimit() throws ParsingException {
|
||||||
|
assertTrue(extractor.getAgeLimit() == 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetTitle() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getTitle().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDescription() throws ParsingException {
|
||||||
|
assertTrue(extractor.getDescription() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploader() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getUploader().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetLength() throws ParsingException {
|
||||||
|
assertTrue(extractor.getLength() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetViews() throws ParsingException {
|
||||||
|
assertTrue(extractor.getLength() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploadDate() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploadDate().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getThumbnailUrl(),
|
||||||
|
extractor.getThumbnailUrl().contains("https://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||||
|
extractor.getUploaderThumbnailUrl().contains("https://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAudioStreams() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getAudioStreams().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetVideoStreams() throws ParsingException {
|
||||||
|
for(VideoStream s : extractor.getVideoStreams()) {
|
||||||
|
assertTrue(s.url,
|
||||||
|
s.url.contains("https://"));
|
||||||
|
assertTrue(s.resolution.length() > 0);
|
||||||
|
assertTrue(Integer.toString(s.format),
|
||||||
|
0 <= s.format && s.format <= 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||||
|
import org.schabi.newpipe.extractor.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 11.03.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubestreamExtractorLiveStreamTest.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 YoutubestreamExtractorLiveStreamTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
|
public void setUp() throws IOException, ExtractionException {
|
||||||
|
//todo: make the extractor not throw over a livestream
|
||||||
|
/*
|
||||||
|
extractor = ServiceList.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=J0s6NjqdjLE", new Downloader());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStreamType() throws ParsingException {
|
||||||
|
assertTrue(true);
|
||||||
|
// assertTrue(extractor.getStreamType() == AbstractVideoInfo.StreamType.LIVE_STREAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -1,16 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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"
|
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.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:logo="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:logo="@mipmap/ic_launcher"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
<activity
|
<activity
|
||||||
@@ -45,6 +48,7 @@
|
|||||||
<data android:host="www.youtube.com" />
|
<data android:host="www.youtube.com" />
|
||||||
<data android:pathPrefix="/v/" />
|
<data android:pathPrefix="/v/" />
|
||||||
<data android:pathPrefix="/watch" />
|
<data android:pathPrefix="/watch" />
|
||||||
|
<data android:pathPrefix="/attribution_link" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -71,20 +75,40 @@
|
|||||||
<data android:scheme="vnd.youtube.launch" />
|
<data android:scheme="vnd.youtube.launch" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".PlayVideoActivity"
|
<activity
|
||||||
|
android:name=".player.PlayVideoActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
android:theme="@style/VideoPlayerTheme"
|
android:theme="@style/VideoPlayerTheme"
|
||||||
android:parentActivityName=".VideoItemDetailActivity"
|
tools:ignore="UnusedAttribute"/>
|
||||||
tools:ignore="UnusedAttribute">
|
<service
|
||||||
|
android:name=".player.BackgroundPlayer"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/background_player_name"/>
|
||||||
|
<activity
|
||||||
|
android:name=".player.ExoPlayerActivity"
|
||||||
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/PlayerTheme">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.schabi.newpipe.exoplayer.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:scheme="content" />
|
||||||
|
<data android:scheme="asset" />
|
||||||
|
<data android:scheme="file" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
<service
|
||||||
android:name=".BackgroundPlayer"
|
android:name=".player.BackgroundPlayer"
|
||||||
android:label="@string/background_player_name"
|
android:label="@string/background_player_name"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".SettingsActivity"
|
android:name=".SettingsActivity"
|
||||||
android:label="@string/title_activity_settings" >
|
android:label="@string/settings_activity_title" />
|
||||||
</activity>
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".PanicResponderActivity"
|
android:name=".PanicResponderActivity"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
@@ -92,11 +116,26 @@
|
|||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="info.guardianproject.panic.action.TRIGGER" />
|
<action android:name="info.guardianproject.panic.action.TRIGGER" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ExitActivity"
|
android:name=".ExitActivity"
|
||||||
|
android:label="@string/general_error"
|
||||||
android:theme="@android:style/Theme.NoDisplay" />
|
android:theme="@android:style/Theme.NoDisplay" />
|
||||||
|
<activity android:name=".ErrorActivity"/>
|
||||||
|
|
||||||
|
<!-- giga get related -->
|
||||||
|
<activity
|
||||||
|
android:name=".download.MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name="us.shandian.giga.service.DownloadManagerService"/>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -22,10 +22,12 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton:
|
* Singleton:
|
||||||
* Used to send data between certain Activity/Services within the same process.
|
* Used to send data between certain Activity/Services within the same process.
|
||||||
* This can be considered as hack inside the Android universe. **/
|
* This can be considered as an ugly hack inside the Android universe. **/
|
||||||
public class ActivityCommunicator {
|
public class ActivityCommunicator {
|
||||||
|
|
||||||
private static ActivityCommunicator activityCommunicator = null;
|
private static ActivityCommunicator activityCommunicator = null;
|
||||||
@@ -39,4 +41,9 @@ public class ActivityCommunicator {
|
|||||||
|
|
||||||
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
||||||
public volatile Bitmap backgroundPlayerThumbnail;
|
public volatile Bitmap backgroundPlayerThumbnail;
|
||||||
|
|
||||||
|
// Sent from any activity to ErrorActivity.
|
||||||
|
public volatile List<Exception> errorList;
|
||||||
|
public volatile Class returnActivity;
|
||||||
|
public volatile ErrorActivity.ErrorInfo errorInfo;
|
||||||
}
|
}
|
||||||
|
78
app/src/main/java/org/schabi/newpipe/App.java
Normal file
78
app/src/main/java/org/schabi/newpipe/App.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||||
|
|
||||||
|
import info.guardianproject.netcipher.NetCipher;
|
||||||
|
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
private static boolean useTor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
// Initialize image loader
|
||||||
|
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
|
||||||
|
ImageLoader.getInstance().init(config);
|
||||||
|
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
if(prefs.getBoolean(getString(R.string.use_tor_key), false)) {
|
||||||
|
OrbotHelper.requestStartTor(this);
|
||||||
|
configureTor(true);
|
||||||
|
} else {
|
||||||
|
configureTor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO NOT REMOVE THIS FUNCTION!!!
|
||||||
|
// Otherwise downloadPathPreference has invalid value.
|
||||||
|
SettingsActivity.initSettings(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the proxy settings based on whether Tor should be enabled or not.
|
||||||
|
*/
|
||||||
|
public static void configureTor(boolean enabled) {
|
||||||
|
useTor = enabled;
|
||||||
|
if (useTor) {
|
||||||
|
NetCipher.useTor();
|
||||||
|
} else {
|
||||||
|
NetCipher.setProxy(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkStartTor(Context context) {
|
||||||
|
if (useTor) {
|
||||||
|
OrbotHelper.requestStartTor(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isUsingTor() {
|
||||||
|
return useTor;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,105 +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.os.Environment;
|
|
||||||
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 prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
String suffix = "";
|
|
||||||
String title = arguments.getString(TITLE);
|
|
||||||
String url = "";
|
|
||||||
String downloadFolder = "Download";
|
|
||||||
switch(which) {
|
|
||||||
case 0: // Video
|
|
||||||
suffix = arguments.getString(FILE_SUFFIX_VIDEO);
|
|
||||||
url = arguments.getString(VIDEO_URL);
|
|
||||||
downloadFolder = "Movies";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
suffix = arguments.getString(FILE_SUFFIX_AUDIO);
|
|
||||||
url = arguments.getString(AUDIO_URL);
|
|
||||||
downloadFolder = "Music";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.d(TAG, "lolz");
|
|
||||||
}
|
|
||||||
//to avoid hard-coded string like "/storage/emulated/0/Movies"
|
|
||||||
String downloadPath = prefs.getString(getString(R.string.downloadPathPreference),
|
|
||||||
Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder);
|
|
||||||
final File dir = new File(downloadPath);
|
|
||||||
if(!dir.exists()) {
|
|
||||||
boolean mkdir = dir.mkdir(); //attempt to create directory
|
|
||||||
if(!mkdir && !dir.isDirectory()) {
|
|
||||||
Log.e(TAG, "Cant' create directory named " + dir.toString());
|
|
||||||
//TODO notify user "download directory should be changed" ?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Request request = new DownloadManager.Request(
|
|
||||||
Uri.parse(url));
|
|
||||||
request.setDestinationUri(Uri.fromFile(new File(dir + "/" + title + suffix)));
|
|
||||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
|
||||||
try {
|
|
||||||
dm.enqueue(request);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -3,14 +3,17 @@ package org.schabi.newpipe;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import info.guardianproject.netcipher.NetCipher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 14.08.15.
|
* 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.
|
* Downloader.java is part of NewPipe.
|
||||||
*
|
*
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
@@ -27,70 +30,61 @@ import java.net.UnknownHostException;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Downloader {
|
public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
||||||
|
|
||||||
private static final String USER_AGENT = "Mozilla/5.0";
|
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
|
||||||
|
|
||||||
/**Download the text file at the supplied URL as in download(String),
|
/**Download the text file at the supplied URL as in download(String),
|
||||||
* but set the HTTP header field "Accept-Language" to the supplied 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
|
* @param language the language (usually a 2-character code) to set as the preferred language
|
||||||
* @return the contents of the specified text file*/
|
* @return the contents of the specified text file*/
|
||||||
public static String download(String siteUrl, String language) {
|
public String download(String siteUrl, String language) throws IOException {
|
||||||
String ret = "";
|
URL url = new URL(siteUrl);
|
||||||
try {
|
//HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
URL url = new URL(siteUrl);
|
HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
||||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
con.setRequestProperty("Accept-Language", language);
|
||||||
con.setRequestProperty("Accept-Language", language);
|
return dl(con);
|
||||||
ret = dl(con);
|
|
||||||
}
|
|
||||||
catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Common functionality between download(String url) and download(String url, String language)*/
|
/**Common functionality between download(String url) and download(String url, String language)*/
|
||||||
private static String dl(HttpURLConnection con) throws IOException {
|
private static String dl(HttpsURLConnection con) throws IOException {
|
||||||
StringBuilder response = new StringBuilder();
|
StringBuilder response = new StringBuilder();
|
||||||
|
BufferedReader in = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
con.setRequestMethod("GET");
|
con.setRequestMethod("GET");
|
||||||
con.setRequestProperty("User-Agent", USER_AGENT);
|
con.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
BufferedReader in = new BufferedReader(
|
in = new BufferedReader(
|
||||||
new InputStreamReader(con.getInputStream()));
|
new InputStreamReader(con.getInputStream()));
|
||||||
String inputLine;
|
String inputLine;
|
||||||
|
|
||||||
while((inputLine = in.readLine()) != null) {
|
while((inputLine = in.readLine()) != null) {
|
||||||
response.append(inputLine);
|
response.append(inputLine);
|
||||||
}
|
}
|
||||||
in.close();
|
} catch(UnknownHostException uhe) {//thrown when there's no internet connection
|
||||||
|
throw new IOException("unknown host or no network", uhe);
|
||||||
}
|
|
||||||
catch(UnknownHostException uhe) {//thrown when there's no internet connection
|
|
||||||
uhe.printStackTrace();
|
|
||||||
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
} finally {
|
||||||
|
if(in != null) {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.toString();
|
return response.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Download (via HTTP) the text file located at the supplied URL, and return its contents.
|
/**Download (via HTTP) the text file located at the supplied URL, and return its contents.
|
||||||
* Primarily intended for downloading web pages.
|
* Primarily intended for downloading web pages.
|
||||||
* @param siteUrl the URL of the text file to download
|
* @param siteUrl the URL of the text file to download
|
||||||
* @return the contents of the specified text file*/
|
* @return the contents of the specified text file*/
|
||||||
public static String download(String siteUrl) {
|
public String download(String siteUrl) throws IOException {
|
||||||
String ret = "";
|
URL url = new URL(siteUrl);
|
||||||
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
try {
|
//HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
||||||
URL url = new URL(siteUrl);
|
return dl(con);
|
||||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
|
||||||
ret = dl(con);
|
|
||||||
}
|
|
||||||
catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
419
app/src/main/java/org/schabi/newpipe/ErrorActivity.java
Normal file
419
app/src/main/java/org/schabi/newpipe/ErrorActivity.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,24 @@ import android.content.Intent;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
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 {
|
public class ExitActivity extends Activity {
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -15,14 +14,34 @@ import java.util.Locale;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by chschtsch on 12/29/15.
|
* Created by chschtsch on 12/29/15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Gregory Arkhipov 2015
|
||||||
|
* Localization.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 Localization {
|
public class Localization {
|
||||||
|
|
||||||
|
private Localization() {
|
||||||
|
}
|
||||||
|
|
||||||
public static Locale getPreferredLocale(Context context) {
|
public static Locale getPreferredLocale(Context context) {
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
String languageCode = sp.getString(String.valueOf(R.string.searchLanguage), "en");
|
String languageCode = sp.getString(String.valueOf(R.string.search_language_key),
|
||||||
|
context.getString(R.string.default_language_value));
|
||||||
|
|
||||||
if(languageCode.length() == 2) {
|
if(languageCode.length() == 2) {
|
||||||
return new Locale(languageCode);
|
return new Locale(languageCode);
|
||||||
@@ -39,7 +58,7 @@ public class Localization {
|
|||||||
Locale locale = getPreferredLocale(context);
|
Locale locale = getPreferredLocale(context);
|
||||||
|
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
String viewsString = res.getString(R.string.viewCountText);
|
String viewsString = res.getString(R.string.view_count_text);
|
||||||
|
|
||||||
NumberFormat nf = NumberFormat.getInstance(locale);
|
NumberFormat nf = NumberFormat.getInstance(locale);
|
||||||
String formattedViewCount = nf.format(viewCount);
|
String formattedViewCount = nf.format(viewCount);
|
||||||
@@ -69,7 +88,7 @@ public class Localization {
|
|||||||
|
|
||||||
public static String localizeDate(String date, Context context) {
|
public static String localizeDate(String date, Context context) {
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
String dateString = res.getString(R.string.uploadDateText);
|
String dateString = res.getString(R.string.upload_date_text);
|
||||||
|
|
||||||
String formattedDate = formatDate(date, context);
|
String formattedDate = formatDate(date, context);
|
||||||
return String.format(dateString, formattedDate);
|
return String.format(dateString, formattedDate);
|
||||||
|
97
app/src/main/java/org/schabi/newpipe/NewPipeSettings.java
Normal file
97
app/src/main/java/org/schabi/newpipe/NewPipeSettings.java
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* Created by k3b on 07.01.2016.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* NewPipeSettings.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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import us.shandian.giga.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for global settings
|
||||||
|
*/
|
||||||
|
public class NewPipeSettings {
|
||||||
|
|
||||||
|
private NewPipeSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void initSettings(Context context) {
|
||||||
|
PreferenceManager.setDefaultValues(context, R.xml.settings, false);
|
||||||
|
getVideoDownloadFolder(context);
|
||||||
|
getAudioDownloadFolder(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getVideoDownloadFolder(Context context) {
|
||||||
|
return getFolder(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVideoDownloadPath(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String key = context.getString(R.string.download_path_key);
|
||||||
|
String downloadPath = prefs.getString(key, Environment.DIRECTORY_MOVIES);
|
||||||
|
|
||||||
|
return downloadPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getAudioDownloadFolder(Context context) {
|
||||||
|
return getFolder(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAudioDownloadPath(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String key = context.getString(R.string.download_path_audio_key);
|
||||||
|
String downloadPath = prefs.getString(key, Environment.DIRECTORY_MUSIC);
|
||||||
|
|
||||||
|
return downloadPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDownloadPath(Context context, String fileName)
|
||||||
|
{
|
||||||
|
if(Utility.isVideoFile(fileName)) {
|
||||||
|
return NewPipeSettings.getVideoDownloadPath(context);
|
||||||
|
}
|
||||||
|
return NewPipeSettings.getAudioDownloadPath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getFolder(Context context, int keyID, String defaultDirectoryName) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String key = context.getString(keyID);
|
||||||
|
String downloadPath = prefs.getString(key, null);
|
||||||
|
if ((downloadPath != null) && (!downloadPath.isEmpty())) return new File(downloadPath.trim());
|
||||||
|
|
||||||
|
final File folder = getFolder(defaultDirectoryName);
|
||||||
|
SharedPreferences.Editor spEditor = prefs.edit();
|
||||||
|
spEditor.putString(key
|
||||||
|
, new File(folder,"NewPipe").getAbsolutePath());
|
||||||
|
spEditor.apply();
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static File getFolder(String defaultDirectoryName) {
|
||||||
|
return new File(Environment.getExternalStorageDirectory(),defaultDirectoryName);
|
||||||
|
}
|
||||||
|
}
|
@@ -6,6 +6,25 @@ import android.app.Activity;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class PanicResponderActivity extends Activity {
|
||||||
|
|
||||||
@@ -15,7 +34,6 @@ public class PanicResponderActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
|
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
|
||||||
// TODO explicitly clear the search results once they are restored when the app restarts
|
// TODO explicitly clear the search results once they are restored when the app restarts
|
||||||
|
@@ -1,9 +1,19 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.preference.CheckBoxPreference;
|
||||||
|
import android.preference.EditTextPreference;
|
||||||
|
import android.preference.ListPreference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
@@ -13,6 +23,8 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 31.08.15.
|
* Created by Christian Schabesberger on 31.08.15.
|
||||||
*
|
*
|
||||||
@@ -33,8 +45,9 @@ import android.view.ViewGroup;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class SettingsActivity extends PreferenceActivity {
|
public class SettingsActivity extends PreferenceActivity {
|
||||||
|
|
||||||
|
private static final int REQUEST_INSTALL_ORBOT = 0x1234;
|
||||||
private AppCompatDelegate mDelegate = null;
|
private AppCompatDelegate mDelegate = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,7 +56,10 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
getDelegate().onCreate(savedInstanceBundle);
|
getDelegate().onCreate(savedInstanceBundle);
|
||||||
super.onCreate(savedInstanceBundle);
|
super.onCreate(savedInstanceBundle);
|
||||||
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
ActionBar actionBar = getSupportActionBar();
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
actionBar.setTitle(R.string.settings_title);
|
||||||
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
getFragmentManager().beginTransaction()
|
||||||
.replace(android.R.id.content, new SettingsFragment())
|
.replace(android.R.id.content, new SettingsFragment())
|
||||||
@@ -51,12 +67,110 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SettingsFragment extends PreferenceFragment {
|
public static class SettingsFragment extends PreferenceFragment{
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener prefListener;
|
||||||
|
|
||||||
|
// get keys
|
||||||
|
String DEFAULT_RESOLUTION_PREFERENCE;
|
||||||
|
String DEFAULT_AUDIO_FORMAT_PREFERENCE;
|
||||||
|
String SEARCH_LANGUAGE_PREFERENCE;
|
||||||
|
String DOWNLOAD_PATH_PREFERENCE;
|
||||||
|
String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
||||||
|
String USE_TOR_KEY;
|
||||||
|
|
||||||
|
private ListPreference defaultResolutionPreference;
|
||||||
|
private ListPreference defaultAudioFormatPreference;
|
||||||
|
private ListPreference searchLanguagePreference;
|
||||||
|
private EditTextPreference downloadPathPreference;
|
||||||
|
private EditTextPreference downloadPathAudioPreference;
|
||||||
|
private CheckBoxPreference useTorCheckBox;
|
||||||
|
private SharedPreferences defaultPreferences;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
addPreferencesFromResource(R.xml.settings_screen);
|
addPreferencesFromResource(R.xml.settings);
|
||||||
|
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
|
||||||
|
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
|
|
||||||
|
// get keys
|
||||||
|
DEFAULT_RESOLUTION_PREFERENCE =getString(R.string.default_resolution_key);
|
||||||
|
DEFAULT_AUDIO_FORMAT_PREFERENCE =getString(R.string.default_audio_format_key);
|
||||||
|
SEARCH_LANGUAGE_PREFERENCE =getString(R.string.search_language_key);
|
||||||
|
DOWNLOAD_PATH_PREFERENCE = getString(R.string.download_path_key);
|
||||||
|
DOWNLOAD_PATH_AUDIO_PREFERENCE = getString(R.string.download_path_audio_key);
|
||||||
|
USE_TOR_KEY = getString(R.string.use_tor_key);
|
||||||
|
|
||||||
|
// get pref objects
|
||||||
|
defaultResolutionPreference =
|
||||||
|
(ListPreference) findPreference(DEFAULT_RESOLUTION_PREFERENCE);
|
||||||
|
defaultAudioFormatPreference =
|
||||||
|
(ListPreference) findPreference(DEFAULT_AUDIO_FORMAT_PREFERENCE);
|
||||||
|
searchLanguagePreference =
|
||||||
|
(ListPreference) findPreference(SEARCH_LANGUAGE_PREFERENCE);
|
||||||
|
downloadPathPreference =
|
||||||
|
(EditTextPreference) findPreference(DOWNLOAD_PATH_PREFERENCE);
|
||||||
|
downloadPathAudioPreference =
|
||||||
|
(EditTextPreference) findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
||||||
|
useTorCheckBox = (CheckBoxPreference) findPreference(USE_TOR_KEY);
|
||||||
|
|
||||||
|
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||||
|
String key) {
|
||||||
|
Activity a = getActivity();
|
||||||
|
if(a != null) {
|
||||||
|
updateSummary();
|
||||||
|
|
||||||
|
if (defaultPreferences.getBoolean(USE_TOR_KEY, false)) {
|
||||||
|
if (OrbotHelper.isOrbotInstalled(a)) {
|
||||||
|
App.configureTor(true);
|
||||||
|
OrbotHelper.requestStartTor(a);
|
||||||
|
} else {
|
||||||
|
Intent intent = OrbotHelper.getOrbotInstallIntent(a);
|
||||||
|
a.startActivityForResult(intent, REQUEST_INSTALL_ORBOT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
App.configureTor(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
defaultPreferences.registerOnSharedPreferenceChangeListener(prefListener);
|
||||||
|
|
||||||
|
updateSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is used to show the status of some preference in the description
|
||||||
|
private void updateSummary() {
|
||||||
|
defaultResolutionPreference.setSummary(
|
||||||
|
defaultPreferences.getString(DEFAULT_RESOLUTION_PREFERENCE,
|
||||||
|
getString(R.string.default_resolution_value)));
|
||||||
|
defaultAudioFormatPreference.setSummary(
|
||||||
|
defaultPreferences.getString(DEFAULT_AUDIO_FORMAT_PREFERENCE,
|
||||||
|
getString(R.string.default_audio_format_value)));
|
||||||
|
searchLanguagePreference.setSummary(
|
||||||
|
defaultPreferences.getString(SEARCH_LANGUAGE_PREFERENCE,
|
||||||
|
getString(R.string.default_language_value)));
|
||||||
|
downloadPathPreference.setSummary(
|
||||||
|
defaultPreferences.getString(DOWNLOAD_PATH_PREFERENCE,
|
||||||
|
getString(R.string.download_path_summary)));
|
||||||
|
downloadPathAudioPreference.setSummary(
|
||||||
|
defaultPreferences.getString(DOWNLOAD_PATH_AUDIO_PREFERENCE,
|
||||||
|
getString(R.string.download_path_audio_summary)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
// try to start tor regardless of resultCode since clicking back after
|
||||||
|
// installing the app does not necessarily return RESULT_OK
|
||||||
|
App.configureTor(requestCode == REQUEST_INSTALL_ORBOT
|
||||||
|
&& OrbotHelper.requestStartTor(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,4 +258,8 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void initSettings(Context context) {
|
||||||
|
NewPipeSettings.initSettings(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.support.v4.widget.CursorAdapter;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Madiyar on 23.02.2016.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* SuggestionListAdapter.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 SuggestionListAdapter extends CursorAdapter {
|
||||||
|
|
||||||
|
private String[] columns = new String[]{"_id", "title"};
|
||||||
|
|
||||||
|
public SuggestionListAdapter(Context context) {
|
||||||
|
super(context, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
|
ViewHolder viewHolder;
|
||||||
|
|
||||||
|
View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
|
||||||
|
viewHolder = new ViewHolder();
|
||||||
|
viewHolder.suggestionTitle = (TextView) view.findViewById(android.R.id.text1);
|
||||||
|
view.setTag(viewHolder);
|
||||||
|
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
|
ViewHolder viewHolder = (ViewHolder) view.getTag();
|
||||||
|
viewHolder.suggestionTitle.setText(cursor.getString(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateAdapter(ArrayList<String> suggestions) {
|
||||||
|
MatrixCursor cursor = new MatrixCursor(columns);
|
||||||
|
int i = 0;
|
||||||
|
for (String s : suggestions) {
|
||||||
|
String[] temp = new String[2];
|
||||||
|
temp[0] = Integer.toString(i);
|
||||||
|
temp[1] = s;
|
||||||
|
i++;
|
||||||
|
cursor.addRow(temp);
|
||||||
|
}
|
||||||
|
changeCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSuggestion(int position) {
|
||||||
|
return ((Cursor) getItem(position)).getString(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder {
|
||||||
|
public TextView suggestionTitle;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +1,17 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||||
|
import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 24.10.15.
|
* Created by Christian Schabesberger on 24.10.15.
|
||||||
*
|
*
|
||||||
@@ -27,15 +32,19 @@ import android.widget.TextView;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class VideoInfoItemViewCreator {
|
public class VideoInfoItemViewCreator {
|
||||||
private final LayoutInflater inflater;
|
private final LayoutInflater inflater;
|
||||||
|
private ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
|
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
||||||
|
|
||||||
public VideoInfoItemViewCreator(LayoutInflater inflater) {
|
public VideoInfoItemViewCreator(LayoutInflater inflater) {
|
||||||
this.inflater = inflater;
|
this.inflater = inflater;
|
||||||
}
|
}
|
||||||
|
|
||||||
public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info, Context context) {
|
public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, StreamPreviewInfo info) {
|
||||||
ViewHolder holder;
|
ViewHolder holder;
|
||||||
|
|
||||||
|
// generate holder
|
||||||
if(convertView == null) {
|
if(convertView == null) {
|
||||||
convertView = inflater.inflate(R.layout.video_item, parent, false);
|
convertView = inflater.inflate(R.layout.video_item, parent, false);
|
||||||
holder = new ViewHolder();
|
holder = new ViewHolder();
|
||||||
@@ -44,23 +53,48 @@ class VideoInfoItemViewCreator {
|
|||||||
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
|
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
|
||||||
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
|
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
|
||||||
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
|
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
|
||||||
|
holder.itemViewCountView = (TextView) convertView.findViewById(R.id.itemViewCountView);
|
||||||
convertView.setTag(holder);
|
convertView.setTag(holder);
|
||||||
} else {
|
} else {
|
||||||
holder = (ViewHolder) convertView.getTag();
|
holder = (ViewHolder) convertView.getTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fill with information
|
||||||
|
|
||||||
|
/*
|
||||||
if(info.thumbnail == null) {
|
if(info.thumbnail == null) {
|
||||||
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
||||||
} else {
|
} else {
|
||||||
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
|
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
holder.itemVideoTitleView.setText(info.title);
|
holder.itemVideoTitleView.setText(info.title);
|
||||||
holder.itemUploaderView.setText(info.uploader);
|
if(info.uploader != null && !info.uploader.isEmpty()) {
|
||||||
holder.itemDurationView.setText(info.duration);
|
holder.itemUploaderView.setText(info.uploader);
|
||||||
if(!info.upload_date.isEmpty()) {
|
|
||||||
holder.itemUploadDateView.setText(info.upload_date);
|
|
||||||
} else {
|
} else {
|
||||||
holder.itemUploadDateView.setText(Localization.localizeViewCount(info.view_count, context));
|
holder.itemUploaderView.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
if(info.duration > 0) {
|
||||||
|
holder.itemDurationView.setText(getDurationString(info.duration));
|
||||||
|
} else {
|
||||||
|
if(info.stream_type == AbstractVideoInfo.StreamType.LIVE_STREAM) {
|
||||||
|
holder.itemDurationView.setText(R.string.duration_live);
|
||||||
|
} else {
|
||||||
|
holder.itemDurationView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(info.view_count >= 0) {
|
||||||
|
holder.itemViewCountView.setText(shortViewCount(info.view_count));
|
||||||
|
} else {
|
||||||
|
holder.itemViewCountView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if(info.upload_date != null && !info.upload_date.isEmpty()) {
|
||||||
|
holder.itemUploadDateView.setText(info.upload_date + " • ");
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
||||||
|
if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty()) {
|
||||||
|
imageLoader.displayImage(info.thumbnail_url, holder.itemThumbnailView, displayImageOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertView;
|
return convertView;
|
||||||
@@ -68,7 +102,72 @@ class VideoInfoItemViewCreator {
|
|||||||
|
|
||||||
private class ViewHolder {
|
private class ViewHolder {
|
||||||
public ImageView itemThumbnailView;
|
public ImageView itemThumbnailView;
|
||||||
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView;
|
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String shortViewCount(Long viewCount){
|
||||||
|
if(viewCount >= 1000000000){
|
||||||
|
return Long.toString(viewCount/1000000000)+"B views";
|
||||||
|
}else if(viewCount>=1000000){
|
||||||
|
return Long.toString(viewCount/1000000)+"M views";
|
||||||
|
}else if(viewCount>=1000){
|
||||||
|
return Long.toString(viewCount/1000)+"K views";
|
||||||
|
}else {
|
||||||
|
return Long.toString(viewCount)+" views";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDurationString(int duration) {
|
||||||
|
String output = "";
|
||||||
|
int days = duration / (24 * 60 * 60); /* greater than a day */
|
||||||
|
duration %= (24 * 60 * 60);
|
||||||
|
int hours = duration / (60 * 60); /* greater than an hour */
|
||||||
|
duration %= (60 * 60);
|
||||||
|
int minutes = duration / 60;
|
||||||
|
int seconds = duration % 60;
|
||||||
|
|
||||||
|
//handle days
|
||||||
|
if(days > 0) {
|
||||||
|
output = Integer.toString(days) + ":";
|
||||||
|
}
|
||||||
|
// handle hours
|
||||||
|
if(hours > 0 || !output.isEmpty()) {
|
||||||
|
if(hours > 0) {
|
||||||
|
if(hours >= 10 || output.isEmpty()) {
|
||||||
|
output += Integer.toString(hours);
|
||||||
|
} else {
|
||||||
|
output += "0" + Integer.toString(hours);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output += "00";
|
||||||
|
}
|
||||||
|
output += ":";
|
||||||
|
}
|
||||||
|
//handle minutes
|
||||||
|
if(minutes > 0 || !output.isEmpty()) {
|
||||||
|
if(minutes > 0) {
|
||||||
|
if(minutes >= 10 || output.isEmpty()) {
|
||||||
|
output += Integer.toString(minutes);
|
||||||
|
} else {
|
||||||
|
output += "0" + Integer.toString(minutes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output += "00";
|
||||||
|
}
|
||||||
|
output += ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle seconds
|
||||||
|
if(output.isEmpty()) {
|
||||||
|
output += "0:";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(seconds >= 10) {
|
||||||
|
output += Integer.toString(seconds);
|
||||||
|
} else {
|
||||||
|
output += "0" + Integer.toString(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
@@ -10,8 +11,8 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.services.ServiceList;
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
import org.schabi.newpipe.services.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +45,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_videoitem_detail);
|
setContentView(R.layout.activity_videoitem_detail);
|
||||||
|
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||||
// Show the Up button in the action bar.
|
// Show the Up button in the action bar.
|
||||||
try {
|
try {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
@@ -70,9 +71,9 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
|||||||
if (getIntent().getData() != null) {
|
if (getIntent().getData() != null) {
|
||||||
videoUrl = getIntent().getData().toString();
|
videoUrl = getIntent().getData().toString();
|
||||||
StreamingService[] serviceList = ServiceList.getServices();
|
StreamingService[] serviceList = ServiceList.getServices();
|
||||||
//VideoExtractor videoExtractor = null;
|
//StreamExtractor videoExtractor = null;
|
||||||
for (int i = 0; i < serviceList.length; i++) {
|
for (int i = 0; i < serviceList.length; i++) {
|
||||||
if (serviceList[i].acceptUrl(videoUrl)) {
|
if (serviceList[i].getUrlIdHandlerInstance().acceptUrl(videoUrl)) {
|
||||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
|
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
|
||||||
currentStreamingService = i;
|
currentStreamingService = i;
|
||||||
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
|
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
|
||||||
@@ -80,7 +81,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(currentStreamingService == -1) {
|
if(currentStreamingService == -1) {
|
||||||
Toast.makeText(this, R.string.urlNotSupportedText, Toast.LENGTH_LONG)
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
//arguments.putString(VideoItemDetailFragment.VIDEO_URL,
|
//arguments.putString(VideoItemDetailFragment.VIDEO_URL,
|
||||||
@@ -89,7 +90,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.getBoolean(getString(R.string.autoPlayThroughIntent), false));
|
.getBoolean(getString(R.string.autoplay_through_intent_key), false));
|
||||||
} else {
|
} else {
|
||||||
videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL);
|
videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL);
|
||||||
currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1);
|
currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1);
|
||||||
@@ -113,6 +114,12 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
|||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
App.checkStartTor(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -9,6 +8,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
@@ -35,8 +36,7 @@ import java.util.Vector;
|
|||||||
class VideoListAdapter extends BaseAdapter {
|
class VideoListAdapter extends BaseAdapter {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final VideoInfoItemViewCreator viewCreator;
|
private final VideoInfoItemViewCreator viewCreator;
|
||||||
private Vector<VideoPreviewInfo> videoList = new Vector<>();
|
private Vector<StreamPreviewInfo> videoList = new Vector<>();
|
||||||
private Vector<Boolean> downloadedThumbnailList = new Vector<>();
|
|
||||||
private final ListView listView;
|
private final ListView listView;
|
||||||
|
|
||||||
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
|
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
|
||||||
@@ -47,38 +47,20 @@ class VideoListAdapter extends BaseAdapter {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addVideoList(List<VideoPreviewInfo> videos) {
|
public void addVideoList(List<StreamPreviewInfo> videos) {
|
||||||
videoList.addAll(videos);
|
videoList.addAll(videos);
|
||||||
for(int i = 0; i < videos.size(); i++) {
|
|
||||||
downloadedThumbnailList.add(false);
|
|
||||||
}
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearVideoList() {
|
public void clearVideoList() {
|
||||||
videoList = new Vector<>();
|
videoList = new Vector<>();
|
||||||
downloadedThumbnailList = new Vector<>();
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector<VideoPreviewInfo> getVideoList() {
|
public Vector<StreamPreviewInfo> getVideoList() {
|
||||||
return videoList;
|
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
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return videoList.size();
|
return videoList.size();
|
||||||
@@ -96,10 +78,10 @@ class VideoListAdapter extends BaseAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context);
|
convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position));
|
||||||
|
|
||||||
if(listView.isItemChecked(position)) {
|
if(listView.isItemChecked(position)) {
|
||||||
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube));
|
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.light_youtube_primary_color));
|
||||||
} else {
|
} else {
|
||||||
convertView.setBackgroundColor(0);
|
convertView.setBackgroundColor(0);
|
||||||
}
|
}
|
||||||
|
@@ -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];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
|||||||
|
package org.schabi.newpipe.download;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import info.guardianproject.netcipher.NetCipher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 14.08.15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* FileDownloader.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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: FOR HEVEN SAKE !!! DO NOT SIMPLY USE ASYNCTASK. MAKE THIS A PROPER SERVICE !!!
|
||||||
|
public class FileDownloader extends AsyncTask<Void, Integer, Void> {
|
||||||
|
public static final String TAG = "FileDownloader";
|
||||||
|
|
||||||
|
|
||||||
|
private NotificationManager nm;
|
||||||
|
private NotificationCompat.Builder builder;
|
||||||
|
private int notifyId = 0x1234;
|
||||||
|
private int fileSize = 0xffffffff;
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private final String fileURL;
|
||||||
|
private final File saveFilePath;
|
||||||
|
private final String title;
|
||||||
|
|
||||||
|
private final String debugContext;
|
||||||
|
|
||||||
|
public FileDownloader(Context context, String fileURL, File saveFilePath, String title) {
|
||||||
|
this.context = context;
|
||||||
|
this.fileURL = fileURL;
|
||||||
|
this.saveFilePath = saveFilePath;
|
||||||
|
this.title = title;
|
||||||
|
|
||||||
|
this.debugContext = "'" + fileURL +
|
||||||
|
"' => '" + saveFilePath + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a file from a URL in the background using an {@link AsyncTask}.
|
||||||
|
*
|
||||||
|
* @param fileURL HTTP URL of the file to be downloaded
|
||||||
|
* @param saveFilePath path of the directory to save the file
|
||||||
|
* @param title
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void downloadFile(final Context context, final String fileURL, final File saveFilePath, String title) {
|
||||||
|
new FileDownloader(context, fileURL, saveFilePath, title).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** AsyncTask impl: executed in gui thread */
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
super.onPreExecute();
|
||||||
|
nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
Drawable icon = context.getResources().getDrawable(R.mipmap.ic_launcher);
|
||||||
|
builder = new NotificationCompat.Builder(context)
|
||||||
|
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
|
.setLargeIcon(((BitmapDrawable) icon).getBitmap())
|
||||||
|
.setContentTitle(saveFilePath.getName())
|
||||||
|
.setContentText(saveFilePath.getAbsolutePath())
|
||||||
|
.setProgress(fileSize, 0, false);
|
||||||
|
nm.notify(notifyId, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** AsyncTask impl: executed in background thread does the download */
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
HttpsURLConnection con = null;
|
||||||
|
InputStream inputStream = null;
|
||||||
|
FileOutputStream outputStream = null;
|
||||||
|
try {
|
||||||
|
con = NetCipher.getHttpsURLConnection(fileURL);
|
||||||
|
int responseCode = con.getResponseCode();
|
||||||
|
|
||||||
|
// always check HTTP response code first
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
fileSize = con.getContentLength();
|
||||||
|
inputStream = new BufferedInputStream(con.getInputStream());
|
||||||
|
outputStream = new FileOutputStream(saveFilePath);
|
||||||
|
|
||||||
|
int bufferSize = 8192;
|
||||||
|
int downloaded = 0;
|
||||||
|
|
||||||
|
int bytesRead = -1;
|
||||||
|
byte[] buffer = new byte[bufferSize];
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
downloaded += bytesRead;
|
||||||
|
if (downloaded % 50000 < bufferSize) {
|
||||||
|
publishProgress(downloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishProgress(bufferSize);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "No file to download. Server replied HTTP code: ", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (outputStream != null) {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
if (inputStream != null) {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (con != null) {
|
||||||
|
con.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(Integer... progress) {
|
||||||
|
builder.setProgress(fileSize, progress[0], false);
|
||||||
|
nm.notify(notifyId, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void aVoid) {
|
||||||
|
super.onPostExecute(aVoid);
|
||||||
|
nm.cancel(notifyId);
|
||||||
|
}
|
||||||
|
}
|
282
app/src/main/java/org/schabi/newpipe/download/MainActivity.java
Normal file
282
app/src/main/java/org/schabi/newpipe/download/MainActivity.java
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user