mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-09-22 10:00:55 +02:00
Compare commits
486 Commits
v0.19.6-fd
...
v0.20.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
175652f23b | ||
![]() |
3329e0c4a1 | ||
![]() |
ea0a0c7c5a | ||
![]() |
535a0504d8 | ||
![]() |
365c49d6d2 | ||
![]() |
b70bea48f2 | ||
![]() |
996f8644c4 | ||
![]() |
b3882ec6e3 | ||
![]() |
f87d447397 | ||
![]() |
9d8570d0d2 | ||
![]() |
796755dad8 | ||
![]() |
9387753995 | ||
![]() |
618d36dc07 | ||
![]() |
f11b0be483 | ||
![]() |
1b8b15b136 | ||
![]() |
bb63673cce | ||
![]() |
6770ad68d5 | ||
![]() |
bfe90c58d1 | ||
![]() |
f1cbeb3c29 | ||
![]() |
554ab4ea16 | ||
![]() |
a2becac2e6 | ||
![]() |
67a651f5e9 | ||
![]() |
ac8efe19d8 | ||
![]() |
ffd65d5afa | ||
![]() |
e86677178f | ||
![]() |
3c49a3341a | ||
![]() |
3433b2a73e | ||
![]() |
730988e7b7 | ||
![]() |
2a3b89e596 | ||
![]() |
f1a31bf58c | ||
![]() |
f1b62a9056 | ||
![]() |
dd943d24c8 | ||
![]() |
801320a3f3 | ||
![]() |
222ed2debd | ||
![]() |
7aab782c5f | ||
![]() |
3836f2f353 | ||
![]() |
5bfaa9a5db | ||
![]() |
95581771d6 | ||
![]() |
db5e3f2479 | ||
![]() |
b5a9631bcc | ||
![]() |
4a2d62ece0 | ||
![]() |
c3836decee | ||
![]() |
f7a030c895 | ||
![]() |
f171a692d3 | ||
![]() |
df5e73192b | ||
![]() |
fc1447d614 | ||
![]() |
77fd206b06 | ||
![]() |
23bdc03490 | ||
![]() |
9fe4de5709 | ||
![]() |
54fd601809 | ||
![]() |
71d027a966 | ||
![]() |
8b63aa2fe6 | ||
![]() |
5a35842c28 | ||
![]() |
d6a1ae3b3a | ||
![]() |
be5f4cb562 | ||
![]() |
d8b5464833 | ||
![]() |
5e7bbcd3bc | ||
![]() |
5383e53c4d | ||
![]() |
5b6fc713d6 | ||
![]() |
272be025e1 | ||
![]() |
e4ab250729 | ||
![]() |
4dcca9d5af | ||
![]() |
1988a08631 | ||
![]() |
34de0e569f | ||
![]() |
343d0fa09d | ||
![]() |
8eb6686103 | ||
![]() |
9e9687b5b8 | ||
![]() |
ef888d1afe | ||
![]() |
0e70e1a37a | ||
![]() |
06aaceb673 | ||
![]() |
703a4b7858 | ||
![]() |
32ba2ba83d | ||
![]() |
272b03ed92 | ||
![]() |
ecf19214ee | ||
![]() |
f3eb0c497f | ||
![]() |
c1f29a7565 | ||
![]() |
fb745b9108 | ||
![]() |
9410bf40d3 | ||
![]() |
c7a695cb04 | ||
![]() |
b991d5cab6 | ||
![]() |
42fd318321 | ||
![]() |
903aeec383 | ||
![]() |
8768fe4dcf | ||
![]() |
d8ba2ceed4 | ||
![]() |
ef8a1bcf47 | ||
![]() |
2b1469e02e | ||
![]() |
83ea91586b | ||
![]() |
dbb86d25e1 | ||
![]() |
794c74e514 | ||
![]() |
fbcdaa77e3 | ||
![]() |
dbdc04c45e | ||
![]() |
a4bb22280f | ||
![]() |
c0e1bbbfb6 | ||
![]() |
196b9dc771 | ||
![]() |
09578b4e46 | ||
![]() |
4d88dadf8c | ||
![]() |
d4fda5847d | ||
![]() |
b1ea7d6cbc | ||
![]() |
4e7632949d | ||
![]() |
26a8bd147b | ||
![]() |
dd726fac02 | ||
![]() |
3a3ecc7775 | ||
![]() |
6665d630ec | ||
![]() |
7706d7471a | ||
![]() |
ed87d6b268 | ||
![]() |
ed51c8b318 | ||
![]() |
6ffbb7b1ed | ||
![]() |
06764db118 | ||
![]() |
4864fa3f2d | ||
![]() |
2d25b6a1f4 | ||
![]() |
be76b3d105 | ||
![]() |
81cbeb4b24 | ||
![]() |
f0b658ba14 | ||
![]() |
295836fc7e | ||
![]() |
54e9858148 | ||
![]() |
b68f015825 | ||
![]() |
87ae26ede3 | ||
![]() |
49615f81b4 | ||
![]() |
87ce5140fa | ||
![]() |
3ba9fb375c | ||
![]() |
f4bd20361a | ||
![]() |
54f8a17aac | ||
![]() |
7a1e5026c4 | ||
![]() |
323161c6de | ||
![]() |
1ac4890893 | ||
![]() |
e9c88fecc5 | ||
![]() |
33deaaefac | ||
![]() |
bb6438ebe4 | ||
![]() |
d42af74afa | ||
![]() |
ea1f2f4ad4 | ||
![]() |
95b45651bb | ||
![]() |
0d5730d33e | ||
![]() |
0625a35ddf | ||
![]() |
2d3271ee13 | ||
![]() |
6da2e80027 | ||
![]() |
439edbf85c | ||
![]() |
e0237a0b86 | ||
![]() |
e1845ba603 | ||
![]() |
1cf757d401 | ||
![]() |
14985b1727 | ||
![]() |
6b2788be57 | ||
![]() |
ac888f4cb2 | ||
![]() |
df06cfc4c5 | ||
![]() |
dcba3a681c | ||
![]() |
7fd49c22a8 | ||
![]() |
314287a6d9 | ||
![]() |
f5e7b8f229 | ||
![]() |
de84db070e | ||
![]() |
c1d5a5cd98 | ||
![]() |
160a04c3c7 | ||
![]() |
23bfc30c57 | ||
![]() |
d9329bffd1 | ||
![]() |
bafc1df988 | ||
![]() |
30b8835919 | ||
![]() |
44b19e75f6 | ||
![]() |
2a558ad11d | ||
![]() |
123d8972e1 | ||
![]() |
e550a8ea27 | ||
![]() |
8b29460fed | ||
![]() |
e380d63c57 | ||
![]() |
89b4f2c4d4 | ||
![]() |
6c2f63f738 | ||
![]() |
77c612f0f5 | ||
![]() |
2d06c01192 | ||
![]() |
d13c19f05f | ||
![]() |
3d2ba05c77 | ||
![]() |
6898b9d9a4 | ||
![]() |
a65aaa6b83 | ||
![]() |
b3136c20c4 | ||
![]() |
0ae3dfd9cc | ||
![]() |
0370fa6c00 | ||
![]() |
7ab323b00c | ||
![]() |
541eb70b9c | ||
![]() |
e53e5ca20e | ||
![]() |
609bf64856 | ||
![]() |
a9fafe91a5 | ||
![]() |
0466b320dd | ||
![]() |
5b74d22d0a | ||
![]() |
4152c7f956 | ||
![]() |
d5f603303d | ||
![]() |
fc9c073a60 | ||
![]() |
9a0c2c40bd | ||
![]() |
d0fc9fda71 | ||
![]() |
df9823988e | ||
![]() |
eeb09c074c | ||
![]() |
af0928e2bd | ||
![]() |
d9cf4de3f7 | ||
![]() |
2d6dd4b3be | ||
![]() |
160312393a | ||
![]() |
e3ff9f9c86 | ||
![]() |
95570d796d | ||
![]() |
cd0d58a915 | ||
![]() |
2f1007c725 | ||
![]() |
b53d5d8c00 | ||
![]() |
3c4a4e5384 | ||
![]() |
0e5f85db95 | ||
![]() |
ad3364671d | ||
![]() |
3add24b8aa | ||
![]() |
e0f02d4080 | ||
![]() |
00c4c10472 | ||
![]() |
a2b8cc9dc2 | ||
![]() |
3465002cbb | ||
![]() |
631cb73305 | ||
![]() |
b3b6384bef | ||
![]() |
941ca575fb | ||
![]() |
2d65c3595d | ||
![]() |
b3812d913a | ||
![]() |
adcc420c81 | ||
![]() |
b97ad99bb4 | ||
![]() |
e93a2850d6 | ||
![]() |
411d0691fa | ||
![]() |
c843e77183 | ||
![]() |
093d6e5336 | ||
![]() |
8a3c752d42 | ||
![]() |
b4e073cde7 | ||
![]() |
814efbf8df | ||
![]() |
11e048abb1 | ||
![]() |
34e7855af6 | ||
![]() |
de54dc27ad | ||
![]() |
790133978d | ||
![]() |
b914d67d9d | ||
![]() |
518eb97e3a | ||
![]() |
f41549ccf1 | ||
![]() |
b69e477ecd | ||
![]() |
0062ff9cfa | ||
![]() |
f8de72f59f | ||
![]() |
7317737e90 | ||
![]() |
5b8eda4805 | ||
![]() |
886a949a00 | ||
![]() |
92e13dafe5 | ||
![]() |
c9be812330 | ||
![]() |
59e7ebabfa | ||
![]() |
1afc48fce3 | ||
![]() |
a1e4ef9e8e | ||
![]() |
5ada0ae2c7 | ||
![]() |
a5312c1341 | ||
![]() |
150e156d26 | ||
![]() |
6d38615ea8 | ||
![]() |
011cc7d337 | ||
![]() |
b747d09836 | ||
![]() |
4b7311bafd | ||
![]() |
eeba9c0a5f | ||
![]() |
11d9a037f7 | ||
![]() |
883e4fcd7c | ||
![]() |
2017e6a3e3 | ||
![]() |
bccfe500b3 | ||
![]() |
5846fbabce | ||
![]() |
52e89c1d1c | ||
![]() |
1605e50cef | ||
![]() |
2215ce58a4 | ||
![]() |
a13e6b69e3 | ||
![]() |
1d6370e11c | ||
![]() |
bd34c7ede3 | ||
![]() |
bc8954fbba | ||
![]() |
9cf0bc6c82 | ||
![]() |
71b32fe641 | ||
![]() |
530f745e44 | ||
![]() |
a5a2313851 | ||
![]() |
4e98c2e7f6 | ||
![]() |
14486782dc | ||
![]() |
31814b70da | ||
![]() |
408e819d32 | ||
![]() |
622676f9bc | ||
![]() |
5b631e0387 | ||
![]() |
06d54ef77e | ||
![]() |
6c5ef567ed | ||
![]() |
f86b40302d | ||
![]() |
273c287fbf | ||
![]() |
6cb16be5df | ||
![]() |
a4feb3fc09 | ||
![]() |
ba6c7de35a | ||
![]() |
79e2bb382f | ||
![]() |
0090256ded | ||
![]() |
00ce077758 | ||
![]() |
a801d0994f | ||
![]() |
628575dc5f | ||
![]() |
0a22f21410 | ||
![]() |
97ff9e9c5b | ||
![]() |
8b3a09306b | ||
![]() |
7766fd13fd | ||
![]() |
c79997ebe3 | ||
![]() |
0fd1e2fcd9 | ||
![]() |
99442b6e04 | ||
![]() |
b8a35e9e4a | ||
![]() |
e833d415e3 | ||
![]() |
8030312924 | ||
![]() |
a84b54f940 | ||
![]() |
c66c81294e | ||
![]() |
bfdc215c65 | ||
![]() |
e10c7beedb | ||
![]() |
18c3286364 | ||
![]() |
8d2ec30818 | ||
![]() |
e5ffddfc6b | ||
![]() |
59fc1e4b5f | ||
![]() |
7ead581953 | ||
![]() |
b860980df4 | ||
![]() |
97a366d62e | ||
![]() |
9ad68097d0 | ||
![]() |
331999fb95 | ||
![]() |
6519d7051d | ||
![]() |
552d585fca | ||
![]() |
24c24d6c72 | ||
![]() |
b7f50c3e12 | ||
![]() |
aed1687a45 | ||
![]() |
daa427dc15 | ||
![]() |
e9d4303fdb | ||
![]() |
5485e994ee | ||
![]() |
87228673b4 | ||
![]() |
d306513319 | ||
![]() |
e08480f345 | ||
![]() |
13c9096417 | ||
![]() |
d3d65c8e3a | ||
![]() |
12ac5ef781 | ||
![]() |
adef9a8acf | ||
![]() |
5ef407d15f | ||
![]() |
970b636eb4 | ||
![]() |
fcf9131aae | ||
![]() |
7fd27fac45 | ||
![]() |
6e17af91fb | ||
![]() |
68555573ad | ||
![]() |
fb9905a89e | ||
![]() |
1e7504dc5a | ||
![]() |
d7af019511 | ||
![]() |
04bb070afa | ||
![]() |
e693d80857 | ||
![]() |
45ae05f1b5 | ||
![]() |
05a83beb44 | ||
![]() |
8a1a42e83b | ||
![]() |
1b3f3cedb3 | ||
![]() |
f815ae5973 | ||
![]() |
fb7035bf22 | ||
![]() |
02bcbc3221 | ||
![]() |
f0a51d4ab4 | ||
![]() |
24fe8fe9a0 | ||
![]() |
244e95d959 | ||
![]() |
ad72c64e32 | ||
![]() |
767ac6a51b | ||
![]() |
3a6f87659a | ||
![]() |
b7ac16c7d9 | ||
![]() |
f9f84cbd89 | ||
![]() |
701c87eefa | ||
![]() |
5379cf0544 | ||
![]() |
6b5c37f17f | ||
![]() |
50b2fad180 | ||
![]() |
b9cb65b24e | ||
![]() |
d7574973e9 | ||
![]() |
ff48c93d59 | ||
![]() |
d2e6700dd1 | ||
![]() |
05b8c3f35f | ||
![]() |
70b643e7ba | ||
![]() |
dce973a519 | ||
![]() |
eb2f75579a | ||
![]() |
773316ce4f | ||
![]() |
5fd7ae33b4 | ||
![]() |
13a065f2dc | ||
![]() |
1a8ff81087 | ||
![]() |
65637fce40 | ||
![]() |
b11fa7a28e | ||
![]() |
45408caf33 | ||
![]() |
963ee4dbab | ||
![]() |
3b46d5a440 | ||
![]() |
212fddd8e1 | ||
![]() |
433485470e | ||
![]() |
e160a1f794 | ||
![]() |
7911b7e637 | ||
![]() |
7fc5a77e7e | ||
![]() |
f0fb55640e | ||
![]() |
d5685f2255 | ||
![]() |
a732233db6 | ||
![]() |
a5918c29ee | ||
![]() |
3b719803bb | ||
![]() |
d77463c9f1 | ||
![]() |
2d8fd9bedf | ||
![]() |
b17a667a9d | ||
![]() |
b7287a070b | ||
![]() |
fbb5c8cdd6 | ||
![]() |
baaf2815e4 | ||
![]() |
d8b5549fd9 | ||
![]() |
6de03f2bf0 | ||
![]() |
caf7c55069 | ||
![]() |
7d499ffba1 | ||
![]() |
4abf6b2f5c | ||
![]() |
a842b06301 | ||
![]() |
0bca4925d7 | ||
![]() |
ae3953cbec | ||
![]() |
a99667c54c | ||
![]() |
465963a8c2 | ||
![]() |
b9b4762faf | ||
![]() |
a56b128a4b | ||
![]() |
d43cc089fd | ||
![]() |
771513d287 | ||
![]() |
c387678217 | ||
![]() |
847368718b | ||
![]() |
458b3daac3 | ||
![]() |
3ea5278b12 | ||
![]() |
20b9748a8c | ||
![]() |
79487adbec | ||
![]() |
89f3fca6b1 | ||
![]() |
f290b2bf5a | ||
![]() |
04e7d13043 | ||
![]() |
e41218c46b | ||
![]() |
8562fbdbbe | ||
![]() |
c841d7a32b | ||
![]() |
8827ae4d2c | ||
![]() |
2e1029e157 | ||
![]() |
a7dc0c2d55 | ||
![]() |
7f1749d853 | ||
![]() |
b4a34d58db | ||
![]() |
4a50fcab2c | ||
![]() |
c9ef089199 | ||
![]() |
94ecf9a081 | ||
![]() |
67aaa9a655 | ||
![]() |
823f5640f7 | ||
![]() |
45d1c63895 | ||
![]() |
d3b6781bb8 | ||
![]() |
21d1f69d6d | ||
![]() |
1b9f5989ef | ||
![]() |
348e46ff3b | ||
![]() |
7918e3a1aa | ||
![]() |
d6d8c7830c | ||
![]() |
f53a0f0d07 | ||
![]() |
17edd1c3d4 | ||
![]() |
b0685c153a | ||
![]() |
a5ca20ee4c | ||
![]() |
03685db2fc | ||
![]() |
68ed738dcd | ||
![]() |
5293d17e32 | ||
![]() |
f2e4b69466 | ||
![]() |
ec8b00042b | ||
![]() |
08db1d59e5 | ||
![]() |
7c79d421e8 | ||
![]() |
7385aa09a8 | ||
![]() |
185a5fad88 | ||
![]() |
a1e2477d14 | ||
![]() |
a1200a5fff | ||
![]() |
91a0257c8f | ||
![]() |
53ffc82fe2 | ||
![]() |
801267df18 | ||
![]() |
6e73e0b395 | ||
![]() |
7aa8a5c368 | ||
![]() |
3ecbbea7cb | ||
![]() |
77cd3182f1 | ||
![]() |
c7ccf9bab8 | ||
![]() |
06e70abb86 | ||
![]() |
88c86e88b0 | ||
![]() |
2d6cf48532 | ||
![]() |
19e152a54b | ||
![]() |
2898bead66 | ||
![]() |
381c329441 | ||
![]() |
a3de3705f7 | ||
![]() |
dc3dc6b77f | ||
![]() |
e028a63f30 | ||
![]() |
d196f8b4b2 | ||
![]() |
4274827dbe | ||
![]() |
7a30f4a7d2 | ||
![]() |
d0c03a0211 | ||
![]() |
787b136d13 | ||
![]() |
08412d6108 | ||
![]() |
d8f7db4715 | ||
![]() |
bff238774e | ||
![]() |
d2aaa6f691 | ||
![]() |
b2164ce5fc | ||
![]() |
5cc60ed760 | ||
![]() |
a7fbe05a73 | ||
![]() |
c796e2ae3c | ||
![]() |
398cbe9284 | ||
![]() |
d87e488c23 | ||
![]() |
5c2ff9b777 | ||
![]() |
6d7e37610c | ||
![]() |
a47e6dd8c5 | ||
![]() |
f334a2740f | ||
![]() |
26e487c01a | ||
![]() |
cc438fdb7b | ||
![]() |
92ff98d99a | ||
![]() |
d1609cba90 | ||
![]() |
0c394b123c | ||
![]() |
421b8214cb | ||
![]() |
6fc91312d2 | ||
![]() |
22bb129bd9 | ||
![]() |
4c57893312 | ||
![]() |
a2d5314cf7 | ||
![]() |
e063967734 | ||
![]() |
4519dd010d | ||
![]() |
bc2dc8d933 | ||
![]() |
fc9b63298c | ||
![]() |
c45514b989 |
1
.github/CONTRIBUTING.md
vendored
1
.github/CONTRIBUTING.md
vendored
@@ -33,6 +33,7 @@ with your GitHub account.
|
|||||||
|
|
||||||
## Code contribution
|
## Code contribution
|
||||||
|
|
||||||
|
* If you want to add a feature or change one, please open an issue describing your change. This gives the team and community a chance to give feedback before you spend any time on something that could be done differently or not done at all. It also prevents two contributors from working on the same thing and one being disappointed when only one user's code can be added.
|
||||||
* Stick to NewPipe's style conventions: follow [checkStyle](https://github.com/checkstyle/checkstyle). It will run each time you build the project.
|
* Stick to NewPipe's style conventions: follow [checkStyle](https://github.com/checkstyle/checkstyle). It will run each time you build the project.
|
||||||
* Do not bring non-free software (e.g. binary blobs) into the project. Also, make sure you do not introduce Google
|
* Do not bring non-free software (e.g. binary blobs) into the project. Also, make sure you do not introduce Google
|
||||||
libraries.
|
libraries.
|
||||||
|
@@ -13,8 +13,8 @@ android {
|
|||||||
resValue "string", "app_name", "NewPipe"
|
resValue "string", "app_name", "NewPipe"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 951
|
versionCode 955
|
||||||
versionName "0.19.6"
|
versionName "0.20.1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@@ -33,7 +33,7 @@ android {
|
|||||||
|
|
||||||
// suffix the app id and the app name with git branch name
|
// suffix the app id and the app name with git branch name
|
||||||
def workingBranch = getGitWorkingBranch()
|
def workingBranch = getGitWorkingBranch()
|
||||||
def normalizedWorkingBranch = workingBranch.replaceAll("[^A-Za-z]+", "").toLowerCase()
|
def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
|
||||||
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
|
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
|
||||||
// default values when branch name could not be determined or is master or dev
|
// default values when branch name could not be determined or is master or dev
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
@@ -84,11 +84,12 @@ ext {
|
|||||||
checkstyleVersion = '8.32'
|
checkstyleVersion = '8.32'
|
||||||
stethoVersion = '1.5.1'
|
stethoVersion = '1.5.1'
|
||||||
leakCanaryVersion = '2.2'
|
leakCanaryVersion = '2.2'
|
||||||
exoPlayerVersion = '2.11.6'
|
exoPlayerVersion = '2.11.8'
|
||||||
androidxLifecycleVersion = '2.2.0'
|
androidxLifecycleVersion = '2.2.0'
|
||||||
androidxRoomVersion = '2.2.5'
|
androidxRoomVersion = '2.2.5'
|
||||||
groupieVersion = '2.8.0'
|
groupieVersion = '2.8.0'
|
||||||
markwonVersion = '4.3.1'
|
markwonVersion = '4.3.1'
|
||||||
|
googleAutoServiceVersion = '1.0-rc7'
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@@ -138,7 +139,7 @@ afterEvaluate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
||||||
implementation "frankiesardo:icepick:${icepickVersion}"
|
implementation "frankiesardo:icepick:${icepickVersion}"
|
||||||
kapt "frankiesardo:icepick-processor:${icepickVersion}"
|
kapt "frankiesardo:icepick-processor:${icepickVersion}"
|
||||||
@@ -163,18 +164,21 @@ dependencies {
|
|||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:a70cb0283ffc3bba2709815673a5a7940aab0a3a'
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:350eed6214b93255d788dfa208b1e9a5e5da91e6'
|
||||||
|
|
||||||
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
|
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
|
||||||
implementation "org.jsoup:jsoup:1.13.1"
|
implementation "org.jsoup:jsoup:1.13.1"
|
||||||
|
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.12.11"
|
implementation "com.squareup.okhttp3:okhttp:3.12.12"
|
||||||
|
|
||||||
implementation "com.google.android.exoplayer:exoplayer:${exoPlayerVersion}"
|
implementation "com.google.android.exoplayer:exoplayer:${exoPlayerVersion}"
|
||||||
implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"
|
implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"
|
||||||
|
|
||||||
implementation "com.google.android.material:material:1.1.0"
|
implementation "com.google.android.material:material:1.1.0"
|
||||||
|
|
||||||
|
compileOnly "com.google.auto.service:auto-service-annotations:${googleAutoServiceVersion}"
|
||||||
|
kapt "com.google.auto.service:auto-service:${googleAutoServiceVersion}"
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:1.1.0"
|
implementation "androidx.appcompat:appcompat:1.1.0"
|
||||||
implementation "androidx.preference:preference:1.1.1"
|
implementation "androidx.preference:preference:1.1.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
@@ -183,7 +187,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:${androidxLifecycleVersion}"
|
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:${androidxRoomVersion}"
|
implementation "androidx.room:room-runtime:${androidxRoomVersion}"
|
||||||
implementation "androidx.room:room-rxjava2:${androidxRoomVersion}"
|
implementation "androidx.room:room-rxjava2:${androidxRoomVersion}"
|
||||||
@@ -206,7 +209,7 @@ dependencies {
|
|||||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||||
implementation "com.jakewharton.rxbinding2:rxbinding:2.2.0"
|
implementation "com.jakewharton.rxbinding2:rxbinding:2.2.0"
|
||||||
|
|
||||||
implementation "org.ocpsoft.prettytime:prettytime:4.0.5.Final"
|
implementation "org.ocpsoft.prettytime:prettytime:4.0.6.Final"
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getGitWorkingBranch() {
|
static String getGitWorkingBranch() {
|
||||||
|
@@ -21,13 +21,13 @@ public class ErrorInfoTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void errorInfoTestParcelable() {
|
public void errorInfoTestParcelable() {
|
||||||
ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request",
|
final ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request",
|
||||||
R.string.general_error);
|
R.string.general_error);
|
||||||
// Obtain a Parcel object and write the parcelable object to it:
|
// Obtain a Parcel object and write the parcelable object to it:
|
||||||
Parcel parcel = Parcel.obtain();
|
final Parcel parcel = Parcel.obtain();
|
||||||
info.writeToParcel(parcel, 0);
|
info.writeToParcel(parcel, 0);
|
||||||
parcel.setDataPosition(0);
|
parcel.setDataPosition(0);
|
||||||
ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
|
final ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
|
||||||
|
|
||||||
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
|
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
|
||||||
assertEquals("youtube", infoFromParcel.serviceName);
|
assertEquals("youtube", infoFromParcel.serviceName);
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package org.schabi.newpipe
|
package org.schabi.newpipe
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.facebook.stetho.Stetho
|
import com.facebook.stetho.Stetho
|
||||||
@@ -11,11 +10,6 @@ import okhttp3.OkHttpClient
|
|||||||
import org.schabi.newpipe.extractor.downloader.Downloader
|
import org.schabi.newpipe.extractor.downloader.Downloader
|
||||||
|
|
||||||
class DebugApp : App() {
|
class DebugApp : App() {
|
||||||
override fun attachBaseContext(base: Context) {
|
|
||||||
super.attachBaseContext(base)
|
|
||||||
MultiDex.install(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
initStetho()
|
initStetho()
|
||||||
@@ -34,6 +28,12 @@ class DebugApp : App() {
|
|||||||
return downloader
|
return downloader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun initACRA() {
|
||||||
|
// install MultiDex before initializing ACRA
|
||||||
|
MultiDex.install(this)
|
||||||
|
super.initACRA()
|
||||||
|
}
|
||||||
|
|
||||||
private fun initStetho() {
|
private fun initStetho() {
|
||||||
// Create an InitializerBuilder
|
// Create an InitializerBuilder
|
||||||
val initializerBuilder = Stetho.newInitializerBuilder(this)
|
val initializerBuilder = Stetho.newInitializerBuilder(this)
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
android:logo="@mipmap/ic_launcher"
|
android:logo="@mipmap/ic_launcher"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:theme="@style/OpeningTheme"
|
android:theme="@style/OpeningTheme"
|
||||||
|
android:resizeableActivity="true"
|
||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@@ -43,8 +44,9 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".player.BackgroundPlayer"
|
android:name=".player.MainPlayer"
|
||||||
android:exported="false">
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="mediaPlayback">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -52,25 +54,9 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".player.BackgroundPlayerActivity"
|
android:name=".player.BackgroundPlayerActivity"
|
||||||
android:label="@string/title_activity_background_player"
|
android:label="@string/title_activity_play_queue"
|
||||||
android:launchMode="singleTask" />
|
android:launchMode="singleTask" />
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".player.PopupVideoPlayerActivity"
|
|
||||||
android:label="@string/title_activity_popup_player"
|
|
||||||
android:launchMode="singleTask" />
|
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".player.PopupVideoPlayer"
|
|
||||||
android:exported="false" />
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".player.MainVideoPlayer"
|
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:theme="@style/VideoPlayerTheme" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".settings.SettingsActivity"
|
android:name=".settings.SettingsActivity"
|
||||||
android:label="@string/settings" />
|
android:label="@string/settings" />
|
||||||
@@ -334,5 +320,11 @@
|
|||||||
<service
|
<service
|
||||||
android:name=".RouterActivity$FetcherService"
|
android:name=".RouterActivity$FetcherService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<!-- see https://github.com/TeamNewPipe/NewPipe/issues/3947 -->
|
||||||
|
<!-- Version < 3.0. DeX Mode and Screen Mirroring support -->
|
||||||
|
<meta-data android:name="com.samsung.android.keepalive.density" android:value="true"/>
|
||||||
|
<!-- Version >= 3.0. DeX Dual Mode support -->
|
||||||
|
<meta-data android:name="com.samsung.android.multidisplay.keep_process_alive" android:value="true"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@@ -150,7 +150,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
// from its saved state, where the fragment manager has already
|
// from its saved state, where the fragment manager has already
|
||||||
// taken care of restoring the fragments we previously had instantiated.
|
// taken care of restoring the fragments we previously had instantiated.
|
||||||
if (mFragments.size() > position) {
|
if (mFragments.size() > position) {
|
||||||
Fragment f = mFragments.get(position);
|
final Fragment f = mFragments.get(position);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -160,12 +160,12 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
mCurTransaction = mFragmentManager.beginTransaction();
|
mCurTransaction = mFragmentManager.beginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
Fragment fragment = getItem(position);
|
final Fragment fragment = getItem(position);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
|
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
|
||||||
}
|
}
|
||||||
if (mSavedState.size() > position) {
|
if (mSavedState.size() > position) {
|
||||||
Fragment.SavedState fss = mSavedState.get(position);
|
final Fragment.SavedState fss = mSavedState.get(position);
|
||||||
if (fss != null) {
|
if (fss != null) {
|
||||||
fragment.setInitialSavedState(fss);
|
fragment.setInitialSavedState(fss);
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@Override
|
@Override
|
||||||
public void destroyItem(@NonNull final ViewGroup container, final int position,
|
public void destroyItem(@NonNull final ViewGroup container, final int position,
|
||||||
@NonNull final Object object) {
|
@NonNull final Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
final Fragment fragment = (Fragment) object;
|
||||||
|
|
||||||
if (mCurTransaction == null) {
|
if (mCurTransaction == null) {
|
||||||
mCurTransaction = mFragmentManager.beginTransaction();
|
mCurTransaction = mFragmentManager.beginTransaction();
|
||||||
@@ -217,7 +217,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@SuppressWarnings({"ReferenceEquality", "deprecation"})
|
@SuppressWarnings({"ReferenceEquality", "deprecation"})
|
||||||
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
|
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
|
||||||
@NonNull final Object object) {
|
@NonNull final Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
final Fragment fragment = (Fragment) object;
|
||||||
if (fragment != mCurrentPrimaryItem) {
|
if (fragment != mCurrentPrimaryItem) {
|
||||||
if (mCurrentPrimaryItem != null) {
|
if (mCurrentPrimaryItem != null) {
|
||||||
mCurrentPrimaryItem.setMenuVisibility(false);
|
mCurrentPrimaryItem.setMenuVisibility(false);
|
||||||
@@ -267,17 +267,17 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
Bundle state = null;
|
Bundle state = null;
|
||||||
if (mSavedState.size() > 0) {
|
if (mSavedState.size() > 0) {
|
||||||
state = new Bundle();
|
state = new Bundle();
|
||||||
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
|
final Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
|
||||||
mSavedState.toArray(fss);
|
mSavedState.toArray(fss);
|
||||||
state.putParcelableArray("states", fss);
|
state.putParcelableArray("states", fss);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mFragments.size(); i++) {
|
for (int i = 0; i < mFragments.size(); i++) {
|
||||||
Fragment f = mFragments.get(i);
|
final Fragment f = mFragments.get(i);
|
||||||
if (f != null && f.isAdded()) {
|
if (f != null && f.isAdded()) {
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
state = new Bundle();
|
state = new Bundle();
|
||||||
}
|
}
|
||||||
String key = "f" + i;
|
final String key = "f" + i;
|
||||||
mFragmentManager.putFragment(state, key, f);
|
mFragmentManager.putFragment(state, key, f);
|
||||||
|
|
||||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
@@ -294,21 +294,21 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@Override
|
@Override
|
||||||
public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) {
|
public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
Bundle bundle = (Bundle) state;
|
final Bundle bundle = (Bundle) state;
|
||||||
bundle.setClassLoader(loader);
|
bundle.setClassLoader(loader);
|
||||||
Parcelable[] fss = bundle.getParcelableArray("states");
|
final Parcelable[] fss = bundle.getParcelableArray("states");
|
||||||
mSavedState.clear();
|
mSavedState.clear();
|
||||||
mFragments.clear();
|
mFragments.clear();
|
||||||
if (fss != null) {
|
if (fss != null) {
|
||||||
for (int i = 0; i < fss.length; i++) {
|
for (final Parcelable parcelable : fss) {
|
||||||
mSavedState.add((Fragment.SavedState) fss[i]);
|
mSavedState.add((Fragment.SavedState) parcelable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Iterable<String> keys = bundle.keySet();
|
final Iterable<String> keys = bundle.keySet();
|
||||||
for (String key: keys) {
|
for (final String key : keys) {
|
||||||
if (key.startsWith("f")) {
|
if (key.startsWith("f")) {
|
||||||
int index = Integer.parseInt(key.substring(1));
|
final int index = Integer.parseInt(key.substring(1));
|
||||||
Fragment f = mFragmentManager.getFragment(bundle, key);
|
final Fragment f = mFragmentManager.getFragment(bundle, key);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
while (mFragments.size() <= index) {
|
while (mFragments.size() <= index) {
|
||||||
mFragments.add(null);
|
mFragments.add(null);
|
||||||
|
@@ -4,13 +4,17 @@ import android.content.Context;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.OverScroller;
|
import android.widget.OverScroller;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
// See https://stackoverflow.com/questions/56849221#57997489
|
// See https://stackoverflow.com/questions/56849221#57997489
|
||||||
public final class FlingBehavior extends AppBarLayout.Behavior {
|
public final class FlingBehavior extends AppBarLayout.Behavior {
|
||||||
@@ -20,23 +24,28 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean allowScroll = true;
|
||||||
|
private final Rect globalRect = new Rect();
|
||||||
|
private final List<Integer> skipInterceptionOfElements = Arrays.asList(
|
||||||
|
R.id.playQueuePanel, R.id.playbackSeekBar,
|
||||||
|
R.id.playPauseButton, R.id.playPreviousButton, R.id.playNextButton);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onRequestChildRectangleOnScreen(
|
public boolean onRequestChildRectangleOnScreen(
|
||||||
@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final AppBarLayout child,
|
@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final AppBarLayout child,
|
||||||
@NonNull final Rect rectangle, final boolean immediate) {
|
@NonNull final Rect rectangle, final boolean immediate) {
|
||||||
|
|
||||||
focusScrollRect.set(rectangle);
|
focusScrollRect.set(rectangle);
|
||||||
|
|
||||||
coordinatorLayout.offsetDescendantRectToMyCoords(child, focusScrollRect);
|
coordinatorLayout.offsetDescendantRectToMyCoords(child, focusScrollRect);
|
||||||
|
|
||||||
int height = coordinatorLayout.getHeight();
|
final int height = coordinatorLayout.getHeight();
|
||||||
|
|
||||||
if (focusScrollRect.top <= 0 && focusScrollRect.bottom >= height) {
|
if (focusScrollRect.top <= 0 && focusScrollRect.bottom >= height) {
|
||||||
// the child is too big to fit inside ourselves completely, ignore request
|
// the child is too big to fit inside ourselves completely, ignore request
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dy;
|
final int dy;
|
||||||
|
|
||||||
if (focusScrollRect.bottom > height) {
|
if (focusScrollRect.bottom > height) {
|
||||||
dy = focusScrollRect.top;
|
dy = focusScrollRect.top;
|
||||||
@@ -48,13 +57,24 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int consumed = scroll(coordinatorLayout, child, dy, getMaxDragOffset(child), 0);
|
final int consumed = scroll(coordinatorLayout, child, dy, getMaxDragOffset(child), 0);
|
||||||
|
|
||||||
return consumed == dy;
|
return consumed == dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onInterceptTouchEvent(final CoordinatorLayout parent, final AppBarLayout child,
|
public boolean onInterceptTouchEvent(final CoordinatorLayout parent, final AppBarLayout child,
|
||||||
final MotionEvent ev) {
|
final MotionEvent ev) {
|
||||||
|
for (final Integer element : skipInterceptionOfElements) {
|
||||||
|
final View view = child.findViewById(element);
|
||||||
|
if (view != null) {
|
||||||
|
final boolean visible = view.getGlobalVisibleRect(globalRect);
|
||||||
|
if (visible && globalRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
|
||||||
|
allowScroll = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allowScroll = true;
|
||||||
switch (ev.getActionMasked()) {
|
switch (ev.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
// remove reference to old nested scrolling child
|
// remove reference to old nested scrolling child
|
||||||
@@ -68,17 +88,37 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
return super.onInterceptTouchEvent(parent, child, ev);
|
return super.onInterceptTouchEvent(parent, child, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onStartNestedScroll(@NonNull final CoordinatorLayout parent,
|
||||||
|
@NonNull final AppBarLayout child,
|
||||||
|
@NonNull final View directTargetChild,
|
||||||
|
final View target,
|
||||||
|
final int nestedScrollAxes,
|
||||||
|
final int type) {
|
||||||
|
return allowScroll && super.onStartNestedScroll(
|
||||||
|
parent, child, directTargetChild, target, nestedScrollAxes, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onNestedFling(@NonNull final CoordinatorLayout coordinatorLayout,
|
||||||
|
@NonNull final AppBarLayout child,
|
||||||
|
@NonNull final View target, final float velocityX,
|
||||||
|
final float velocityY, final boolean consumed) {
|
||||||
|
return allowScroll && super.onNestedFling(
|
||||||
|
coordinatorLayout, child, target, velocityX, velocityY, consumed);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private OverScroller getScrollerField() {
|
private OverScroller getScrollerField() {
|
||||||
try {
|
try {
|
||||||
Class<?> headerBehaviorType = this.getClass()
|
final Class<?> headerBehaviorType = this.getClass()
|
||||||
.getSuperclass().getSuperclass().getSuperclass();
|
.getSuperclass().getSuperclass().getSuperclass();
|
||||||
if (headerBehaviorType != null) {
|
if (headerBehaviorType != null) {
|
||||||
Field field = headerBehaviorType.getDeclaredField("scroller");
|
final Field field = headerBehaviorType.getDeclaredField("scroller");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
return ((OverScroller) field.get(this));
|
return ((OverScroller) field.get(this));
|
||||||
}
|
}
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -87,34 +127,35 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Field getLastNestedScrollingChildRefField() {
|
private Field getLastNestedScrollingChildRefField() {
|
||||||
try {
|
try {
|
||||||
Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
|
final Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
|
||||||
if (headerBehaviorType != null) {
|
if (headerBehaviorType != null) {
|
||||||
Field field = headerBehaviorType.getDeclaredField("lastNestedScrollingChildRef");
|
final Field field
|
||||||
|
= headerBehaviorType.getDeclaredField("lastNestedScrollingChildRef");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (final NoSuchFieldException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetNestedScrollingChild() {
|
private void resetNestedScrollingChild() {
|
||||||
Field field = getLastNestedScrollingChildRefField();
|
final Field field = getLastNestedScrollingChildRefField();
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
try {
|
try {
|
||||||
Object value = field.get(this);
|
final Object value = field.get(this);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
field.set(this, null);
|
field.set(this, null);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (final IllegalAccessException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopAppBarLayoutFling() {
|
private void stopAppBarLayoutFling() {
|
||||||
OverScroller scroller = getScrollerField();
|
final OverScroller scroller = getScrollerField();
|
||||||
if (scroller != null) {
|
if (scroller != null) {
|
||||||
scroller.forceFinished(true);
|
scroller.forceFinished(true);
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
|
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
|
||||||
@@ -19,10 +20,8 @@ import org.acra.ACRA;
|
|||||||
import org.acra.config.ACRAConfigurationException;
|
import org.acra.config.ACRAConfigurationException;
|
||||||
import org.acra.config.CoreConfiguration;
|
import org.acra.config.CoreConfiguration;
|
||||||
import org.acra.config.CoreConfigurationBuilder;
|
import org.acra.config.CoreConfigurationBuilder;
|
||||||
import org.acra.sender.ReportSenderFactory;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
@@ -37,7 +36,6 @@ import java.net.SocketException;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.annotations.NonNull;
|
|
||||||
import io.reactivex.exceptions.CompositeException;
|
import io.reactivex.exceptions.CompositeException;
|
||||||
import io.reactivex.exceptions.MissingBackpressureException;
|
import io.reactivex.exceptions.MissingBackpressureException;
|
||||||
import io.reactivex.exceptions.OnErrorNotImplementedException;
|
import io.reactivex.exceptions.OnErrorNotImplementedException;
|
||||||
@@ -65,9 +63,6 @@ import io.reactivex.plugins.RxJavaPlugins;
|
|||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
protected static final String TAG = App.class.toString();
|
protected static final String TAG = App.class.toString();
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static final Class<? extends ReportSenderFactory>[]
|
|
||||||
REPORT_SENDER_FACTORY_CLASSES = new Class[]{AcraReportSenderFactory.class};
|
|
||||||
private static App app;
|
private static App app;
|
||||||
|
|
||||||
public static App getApp() {
|
public static App getApp() {
|
||||||
@@ -77,7 +72,6 @@ public class App extends Application {
|
|||||||
@Override
|
@Override
|
||||||
protected void attachBaseContext(final Context base) {
|
protected void attachBaseContext(final Context base) {
|
||||||
super.attachBaseContext(base);
|
super.attachBaseContext(base);
|
||||||
|
|
||||||
initACRA();
|
initACRA();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +104,7 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Downloader getDownloader() {
|
protected Downloader getDownloader() {
|
||||||
DownloaderImpl downloader = DownloaderImpl.init(null);
|
final DownloaderImpl downloader = DownloaderImpl.init(null);
|
||||||
setCookiesToDownloader(downloader);
|
setCookiesToDownloader(downloader);
|
||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
@@ -200,14 +194,21 @@ public class App extends Application {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initACRA() {
|
/**
|
||||||
|
* Called in {@link #attachBaseContext(Context)} after calling the {@code super} method.
|
||||||
|
* Should be overridden if MultiDex is enabled, since it has to be initialized before ACRA.
|
||||||
|
*/
|
||||||
|
protected void initACRA() {
|
||||||
|
if (ACRA.isACRASenderServiceProcess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final CoreConfiguration acraConfig = new CoreConfigurationBuilder(this)
|
final CoreConfiguration acraConfig = new CoreConfigurationBuilder(this)
|
||||||
.setReportSenderFactoryClasses(REPORT_SENDER_FACTORY_CLASSES)
|
|
||||||
.setBuildConfigClass(BuildConfig.class)
|
.setBuildConfigClass(BuildConfig.class)
|
||||||
.build();
|
.build();
|
||||||
ACRA.init(this, acraConfig);
|
ACRA.init(this, acraConfig);
|
||||||
} catch (ACRAConfigurationException ace) {
|
} catch (final ACRAConfigurationException ace) {
|
||||||
ace.printStackTrace();
|
ace.printStackTrace();
|
||||||
ErrorActivity.reportError(this,
|
ErrorActivity.reportError(this,
|
||||||
ace,
|
ace,
|
||||||
@@ -219,7 +220,7 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initNotificationChannel() {
|
public void initNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,10 +231,10 @@ public class App extends Application {
|
|||||||
// Keep this below DEFAULT to avoid making noise on every notification update
|
// Keep this below DEFAULT to avoid making noise on every notification update
|
||||||
final int importance = NotificationManager.IMPORTANCE_LOW;
|
final int importance = NotificationManager.IMPORTANCE_LOW;
|
||||||
|
|
||||||
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
|
final NotificationChannel mChannel = new NotificationChannel(id, name, importance);
|
||||||
mChannel.setDescription(description);
|
mChannel.setDescription(description);
|
||||||
|
|
||||||
NotificationManager mNotificationManager =
|
final NotificationManager mNotificationManager =
|
||||||
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
mNotificationManager.createNotificationChannel(mChannel);
|
mNotificationManager.createNotificationChannel(mChannel);
|
||||||
|
|
||||||
@@ -254,11 +255,11 @@ public class App extends Application {
|
|||||||
final String appUpdateDescription
|
final String appUpdateDescription
|
||||||
= getString(R.string.app_update_notification_channel_description);
|
= getString(R.string.app_update_notification_channel_description);
|
||||||
|
|
||||||
NotificationChannel appUpdateChannel
|
final NotificationChannel appUpdateChannel
|
||||||
= new NotificationChannel(appUpdateId, appUpdateName, importance);
|
= new NotificationChannel(appUpdateId, appUpdateName, importance);
|
||||||
appUpdateChannel.setDescription(appUpdateDescription);
|
appUpdateChannel.setDescription(appUpdateDescription);
|
||||||
|
|
||||||
NotificationManager appUpdateNotificationManager
|
final NotificationManager appUpdateNotificationManager
|
||||||
= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
appUpdateNotificationManager.createNotificationChannel(appUpdateChannel);
|
appUpdateNotificationManager.createNotificationChannel(appUpdateChannel);
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ import android.content.pm.Signature;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
@@ -62,7 +62,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
packageInfo = pm.getPackageInfo(packageName, flags);
|
packageInfo = pm.getPackageInfo(packageName, flags);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(APP, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Could not find package info", R.string.app_ui_crash));
|
"Could not find package info", R.string.app_ui_crash));
|
||||||
@@ -77,7 +77,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
try {
|
try {
|
||||||
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
||||||
c = (X509Certificate) cf.generateCertificate(input);
|
c = (X509Certificate) cf.generateCertificate(input);
|
||||||
} catch (CertificateException e) {
|
} catch (final CertificateException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(APP, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Certificate error", R.string.app_ui_crash));
|
"Certificate error", R.string.app_ui_crash));
|
||||||
@@ -86,7 +86,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
String hexString = null;
|
String hexString = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
final MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||||
final byte[] publicKey = md.digest(c.getEncoded());
|
final byte[] publicKey = md.digest(c.getEncoded());
|
||||||
hexString = byte2HexFormatted(publicKey);
|
hexString = byte2HexFormatted(publicKey);
|
||||||
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
||||||
@@ -167,7 +167,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
|
|
||||||
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
||||||
|
|
||||||
} catch (JsonParserException e) {
|
} catch (final JsonParserException e) {
|
||||||
// connectivity problems, do not alarm user and fail silently
|
// connectivity problems, do not alarm user and fail silently
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.w(TAG, Log.getStackTraceString(e));
|
Log.w(TAG, Log.getStackTraceString(e));
|
||||||
@@ -187,7 +187,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
private void compareAppVersionAndShowNotification(final String versionName,
|
private void compareAppVersionAndShowNotification(final String versionName,
|
||||||
final String apkLocationUrl,
|
final String apkLocationUrl,
|
||||||
final int versionCode) {
|
final int versionCode) {
|
||||||
int notificationId = 2000;
|
final int notificationId = 2000;
|
||||||
|
|
||||||
if (BuildConfig.VERSION_CODE < versionCode) {
|
if (BuildConfig.VERSION_CODE < versionCode) {
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -94,18 +94,18 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
private static void enableModernTLS(final OkHttpClient.Builder builder) {
|
private static void enableModernTLS(final OkHttpClient.Builder builder) {
|
||||||
try {
|
try {
|
||||||
// get the default TrustManager
|
// get the default TrustManager
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
|
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
|
||||||
TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init((KeyStore) null);
|
trustManagerFactory.init((KeyStore) null);
|
||||||
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
||||||
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
||||||
throw new IllegalStateException("Unexpected default trust managers:"
|
throw new IllegalStateException("Unexpected default trust managers:"
|
||||||
+ Arrays.toString(trustManagers));
|
+ Arrays.toString(trustManagers));
|
||||||
}
|
}
|
||||||
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
|
final X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
|
||||||
|
|
||||||
// insert our own TLSSocketFactory
|
// insert our own TLSSocketFactory
|
||||||
SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance();
|
final SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance();
|
||||||
|
|
||||||
builder.sslSocketFactory(sslSocketFactory, trustManager);
|
builder.sslSocketFactory(sslSocketFactory, trustManager);
|
||||||
|
|
||||||
@@ -114,16 +114,16 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
// Necessary because some servers (e.g. Framatube.org)
|
// Necessary because some servers (e.g. Framatube.org)
|
||||||
// don't support the old cipher suites.
|
// don't support the old cipher suites.
|
||||||
// https://github.com/square/okhttp/issues/4053#issuecomment-402579554
|
// https://github.com/square/okhttp/issues/4053#issuecomment-402579554
|
||||||
List<CipherSuite> cipherSuites = new ArrayList<>();
|
final List<CipherSuite> cipherSuites =
|
||||||
cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites());
|
new ArrayList<>(ConnectionSpec.MODERN_TLS.cipherSuites());
|
||||||
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
|
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
|
||||||
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
|
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
|
||||||
ConnectionSpec legacyTLS = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
final ConnectionSpec legacyTLS = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||||
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
|
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
builder.connectionSpecs(Arrays.asList(legacyTLS, ConnectionSpec.CLEARTEXT));
|
builder.connectionSpecs(Arrays.asList(legacyTLS, ConnectionSpec.CLEARTEXT));
|
||||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
} catch (final KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -131,15 +131,15 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getCookies(final String url) {
|
public String getCookies(final String url) {
|
||||||
List<String> resultCookies = new ArrayList<>();
|
final List<String> resultCookies = new ArrayList<>();
|
||||||
if (url.contains(YOUTUBE_DOMAIN)) {
|
if (url.contains(YOUTUBE_DOMAIN)) {
|
||||||
String youtubeCookie = getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY);
|
final String youtubeCookie = getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY);
|
||||||
if (youtubeCookie != null) {
|
if (youtubeCookie != null) {
|
||||||
resultCookies.add(youtubeCookie);
|
resultCookies.add(youtubeCookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recaptcha cookie is always added TODO: not sure if this is necessary
|
// Recaptcha cookie is always added TODO: not sure if this is necessary
|
||||||
String recaptchaCookie = getCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY);
|
final String recaptchaCookie = getCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY);
|
||||||
if (recaptchaCookie != null) {
|
if (recaptchaCookie != null) {
|
||||||
resultCookies.add(recaptchaCookie);
|
resultCookies.add(recaptchaCookie);
|
||||||
}
|
}
|
||||||
@@ -159,9 +159,9 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateYoutubeRestrictedModeCookies(final Context context) {
|
public void updateYoutubeRestrictedModeCookies(final Context context) {
|
||||||
String restrictedModeEnabledKey =
|
final String restrictedModeEnabledKey =
|
||||||
context.getString(R.string.youtube_restricted_mode_enabled);
|
context.getString(R.string.youtube_restricted_mode_enabled);
|
||||||
boolean restrictedModeEnabled = PreferenceManager.getDefaultSharedPreferences(context)
|
final boolean restrictedModeEnabled = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getBoolean(restrictedModeEnabledKey, false);
|
.getBoolean(restrictedModeEnabledKey, false);
|
||||||
updateYoutubeRestrictedModeCookies(restrictedModeEnabled);
|
updateYoutubeRestrictedModeCookies(restrictedModeEnabled);
|
||||||
}
|
}
|
||||||
@@ -186,9 +186,9 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
try {
|
try {
|
||||||
final Response response = head(url);
|
final Response response = head(url);
|
||||||
return Long.parseLong(response.getHeader("Content-Length"));
|
return Long.parseLong(response.getHeader("Content-Length"));
|
||||||
} catch (NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
throw new IOException("Invalid content length", e);
|
throw new IOException("Invalid content length", e);
|
||||||
} catch (ReCaptchaException e) {
|
} catch (final ReCaptchaException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
.method("GET", null).url(siteUrl)
|
.method("GET", null).url(siteUrl)
|
||||||
.addHeader("User-Agent", USER_AGENT);
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
String cookies = getCookies(siteUrl);
|
final String cookies = getCookies(siteUrl);
|
||||||
if (!cookies.isEmpty()) {
|
if (!cookies.isEmpty()) {
|
||||||
requestBuilder.addHeader("Cookie", cookies);
|
requestBuilder.addHeader("Cookie", cookies);
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,7 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return body.byteStream();
|
return body.byteStream();
|
||||||
} catch (ReCaptchaException e) {
|
} catch (final ReCaptchaException e) {
|
||||||
throw new IOException(e.getMessage(), e.getCause());
|
throw new IOException(e.getMessage(), e.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,18 +240,18 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
.method(httpMethod, requestBody).url(url)
|
.method(httpMethod, requestBody).url(url)
|
||||||
.addHeader("User-Agent", USER_AGENT);
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
String cookies = getCookies(url);
|
final String cookies = getCookies(url);
|
||||||
if (!cookies.isEmpty()) {
|
if (!cookies.isEmpty()) {
|
||||||
requestBuilder.addHeader("Cookie", cookies);
|
requestBuilder.addHeader("Cookie", cookies);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, List<String>> pair : headers.entrySet()) {
|
for (final Map.Entry<String, List<String>> pair : headers.entrySet()) {
|
||||||
final String headerName = pair.getKey();
|
final String headerName = pair.getKey();
|
||||||
final List<String> headerValueList = pair.getValue();
|
final List<String> headerValueList = pair.getValue();
|
||||||
|
|
||||||
if (headerValueList.size() > 1) {
|
if (headerValueList.size() > 1) {
|
||||||
requestBuilder.removeHeader(headerName);
|
requestBuilder.removeHeader(headerName);
|
||||||
for (String headerValue : headerValueList) {
|
for (final String headerValue : headerValueList) {
|
||||||
requestBuilder.addHeader(headerName, headerValue);
|
requestBuilder.addHeader(headerName, headerValue);
|
||||||
}
|
}
|
||||||
} else if (headerValueList.size() == 1) {
|
} else if (headerValueList.size() == 1) {
|
||||||
|
@@ -27,7 +27,7 @@ import android.os.Bundle;
|
|||||||
public class ExitActivity extends Activity {
|
public class ExitActivity extends Activity {
|
||||||
|
|
||||||
public static void exitAndRemoveFromRecentApps(final Activity activity) {
|
public static void exitAndRemoveFromRecentApps(final Activity activity) {
|
||||||
Intent intent = new Intent(activity, ExitActivity.class);
|
final Intent intent = new Intent(activity, ExitActivity.class);
|
||||||
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
||||||
@@ -42,7 +42,7 @@ public class ExitActivity extends Activity {
|
|||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
finishAndRemoveTask();
|
finishAndRemoveTask();
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
|
@@ -4,7 +4,7 @@ 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;
|
||||||
import android.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,7 @@ public final class NewPipeDatabase {
|
|||||||
if (databaseInstance == null) {
|
if (databaseInstance == null) {
|
||||||
throw new IllegalStateException("database is not initialized");
|
throw new IllegalStateException("database is not initialized");
|
||||||
}
|
}
|
||||||
Cursor c = databaseInstance.query("pragma wal_checkpoint(full)", null);
|
final Cursor c = databaseInstance.query("pragma wal_checkpoint(full)", null);
|
||||||
if (c.moveToFirst() && c.getInt(0) == 1) {
|
if (c.moveToFirst() && c.getInt(0) == 1) {
|
||||||
throw new RuntimeException("Checkpoint was blocked from completing");
|
throw new RuntimeException("Checkpoint was blocked from completing");
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ public class PanicResponderActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Intent intent = getIntent();
|
final 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
|
// TODO: Explicitly clear the search results
|
||||||
// once they are restored when the app restarts
|
// once they are restored when the app restarts
|
||||||
@@ -40,7 +40,7 @@ public class PanicResponderActivity extends Activity {
|
|||||||
ExitActivity.exitAndRemoveFromRecentApps(this);
|
ExitActivity.exitAndRemoveFromRecentApps(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
finishAndRemoveTask();
|
finishAndRemoveTask();
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
|
@@ -61,7 +61,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
ThemeHelper.setTheme(this);
|
ThemeHelper.setTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_recaptcha);
|
setContentView(R.layout.activity_recaptcha);
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
String url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
|
String url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
|
||||||
@@ -76,7 +76,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
webView = findViewById(R.id.reCaptchaWebView);
|
webView = findViewById(R.id.reCaptchaWebView);
|
||||||
|
|
||||||
// enable Javascript
|
// enable Javascript
|
||||||
WebSettings webSettings = webView.getSettings();
|
final WebSettings webSettings = webView.getSettings();
|
||||||
webSettings.setJavaScriptEnabled(true);
|
webSettings.setJavaScriptEnabled(true);
|
||||||
|
|
||||||
webView.setWebViewClient(new WebViewClient() {
|
webView.setWebViewClient(new WebViewClient() {
|
||||||
@@ -84,7 +84,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldOverrideUrlLoading(final WebView view,
|
public boolean shouldOverrideUrlLoading(final WebView view,
|
||||||
final WebResourceRequest request) {
|
final WebResourceRequest request) {
|
||||||
String url = request.getUrl().toString();
|
final String url = request.getUrl().toString();
|
||||||
if (MainActivity.DEBUG) {
|
if (MainActivity.DEBUG) {
|
||||||
Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
|
Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
// cleaning cache, history and cookies from webView
|
// cleaning cache, history and cookies from webView
|
||||||
webView.clearCache(true);
|
webView.clearCache(true);
|
||||||
webView.clearHistory();
|
webView.clearHistory();
|
||||||
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
final android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
cookieManager.removeAllCookies(aBoolean -> {
|
cookieManager.removeAllCookies(aBoolean -> {
|
||||||
});
|
});
|
||||||
@@ -128,7 +128,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.menu_recaptcha, menu);
|
getMenuInflater().inflate(R.menu.menu_recaptcha, menu);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
actionBar.setTitle(R.string.title_activity_recaptcha);
|
actionBar.setTitle(R.string.title_activity_recaptcha);
|
||||||
@@ -145,7 +145,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case R.id.menu_item_done:
|
case R.id.menu_item_done:
|
||||||
saveCookiesAndFinish();
|
saveCookiesAndFinish();
|
||||||
@@ -173,7 +173,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
|
final Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
NavUtils.navigateUpTo(this, intent);
|
NavUtils.navigateUpTo(this, intent);
|
||||||
}
|
}
|
||||||
@@ -188,13 +188,13 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String cookies = CookieManager.getInstance().getCookie(url);
|
final String cookies = CookieManager.getInstance().getCookie(url);
|
||||||
handleCookies(cookies);
|
handleCookies(cookies);
|
||||||
|
|
||||||
// sometimes cookies are inside the url
|
// sometimes cookies are inside the url
|
||||||
int abuseStart = url.indexOf("google_abuse=");
|
final int abuseStart = url.indexOf("google_abuse=");
|
||||||
if (abuseStart != -1) {
|
if (abuseStart != -1) {
|
||||||
int abuseEnd = url.indexOf("+path");
|
final int abuseEnd = url.indexOf("+path");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
|
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -88,7 +88,7 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
setContentView(R.layout.activity_about);
|
setContentView(R.layout.activity_about);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
// Create the adapter that will return a fragment for each of the three
|
// Create the adapter that will return a fragment for each of the three
|
||||||
@@ -99,13 +99,13 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
mViewPager = findViewById(R.id.container);
|
mViewPager = findViewById(R.id.container);
|
||||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||||
|
|
||||||
TabLayout tabLayout = findViewById(R.id.tabs);
|
final TabLayout tabLayout = findViewById(R.id.tabs);
|
||||||
tabLayout.setupWithViewPager(mViewPager);
|
tabLayout.setupWithViewPager(mViewPager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
@@ -134,25 +134,25 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
View rootView = inflater.inflate(R.layout.fragment_about, container, false);
|
final View rootView = inflater.inflate(R.layout.fragment_about, container, false);
|
||||||
Context context = this.getContext();
|
final Context context = this.getContext();
|
||||||
|
|
||||||
TextView version = rootView.findViewById(R.id.app_version);
|
final TextView version = rootView.findViewById(R.id.app_version);
|
||||||
version.setText(BuildConfig.VERSION_NAME);
|
version.setText(BuildConfig.VERSION_NAME);
|
||||||
|
|
||||||
View githubLink = rootView.findViewById(R.id.github_link);
|
final View githubLink = rootView.findViewById(R.id.github_link);
|
||||||
githubLink.setOnClickListener(nv ->
|
githubLink.setOnClickListener(nv ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.github_url)));
|
openUrlInBrowser(context, context.getString(R.string.github_url)));
|
||||||
|
|
||||||
View donationLink = rootView.findViewById(R.id.donation_link);
|
final View donationLink = rootView.findViewById(R.id.donation_link);
|
||||||
donationLink.setOnClickListener(v ->
|
donationLink.setOnClickListener(v ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.donation_url)));
|
openUrlInBrowser(context, context.getString(R.string.donation_url)));
|
||||||
|
|
||||||
View websiteLink = rootView.findViewById(R.id.website_link);
|
final View websiteLink = rootView.findViewById(R.id.website_link);
|
||||||
websiteLink.setOnClickListener(nv ->
|
websiteLink.setOnClickListener(nv ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.website_url)));
|
openUrlInBrowser(context, context.getString(R.string.website_url)));
|
||||||
|
|
||||||
View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
|
final View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
|
||||||
privacyPolicyLink.setOnClickListener(v ->
|
privacyPolicyLink.setOnClickListener(v ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url)));
|
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url)));
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
*/
|
*/
|
||||||
public class SectionsPagerAdapter extends FragmentPagerAdapter {
|
public class SectionsPagerAdapter extends FragmentPagerAdapter {
|
||||||
public SectionsPagerAdapter(final FragmentManager fm) {
|
public SectionsPagerAdapter(final FragmentManager fm) {
|
||||||
super(fm);
|
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -4,10 +4,12 @@ import android.net.Uri;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for storing information about a software license.
|
* Class for storing information about a software license.
|
||||||
*/
|
*/
|
||||||
public class License implements Parcelable {
|
public class License implements Parcelable, Serializable {
|
||||||
public static final Creator<License> CREATOR = new Creator<License>() {
|
public static final Creator<License> CREATOR = new Creator<License>() {
|
||||||
@Override
|
@Override
|
||||||
public License createFromParcel(final Parcel source) {
|
public License createFromParcel(final Parcel source) {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe.about;
|
package org.schabi.newpipe.about;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -11,12 +10,14 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.ShareUtils;
|
import org.schabi.newpipe.util.ShareUtils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,13 +27,15 @@ public class LicenseFragment extends Fragment {
|
|||||||
private static final String ARG_COMPONENTS = "components";
|
private static final String ARG_COMPONENTS = "components";
|
||||||
private SoftwareComponent[] softwareComponents;
|
private SoftwareComponent[] softwareComponents;
|
||||||
private SoftwareComponent componentForContextMenu;
|
private SoftwareComponent componentForContextMenu;
|
||||||
|
private License activeLicense;
|
||||||
|
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
|
||||||
|
|
||||||
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
||||||
if (softwareComponents == null) {
|
if (softwareComponents == null) {
|
||||||
throw new NullPointerException("softwareComponents is null");
|
throw new NullPointerException("softwareComponents is null");
|
||||||
}
|
}
|
||||||
LicenseFragment fragment = new LicenseFragment();
|
final LicenseFragment fragment = new LicenseFragment();
|
||||||
Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents);
|
bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents);
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
return fragment;
|
return fragment;
|
||||||
@@ -44,8 +47,8 @@ public class LicenseFragment extends Fragment {
|
|||||||
* @param context the context to use
|
* @param context the context to use
|
||||||
* @param license the license to show
|
* @param license the license to show
|
||||||
*/
|
*/
|
||||||
private static void showLicense(final Context context, final License license) {
|
private static void showLicense(final Activity context, final License license) {
|
||||||
new LicenseFragmentHelper((Activity) context).execute(license);
|
new LicenseFragmentHelper(context).execute(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -54,6 +57,12 @@ public class LicenseFragment extends Fragment {
|
|||||||
softwareComponents = (SoftwareComponent[]) getArguments()
|
softwareComponents = (SoftwareComponent[]) getArguments()
|
||||||
.getParcelableArray(ARG_COMPONENTS);
|
.getParcelableArray(ARG_COMPONENTS);
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
final Serializable license = savedInstanceState.getSerializable(LICENSE_KEY);
|
||||||
|
if (license != null) {
|
||||||
|
activeLicense = (License) license;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Sort components by name
|
// Sort components by name
|
||||||
Arrays.sort(softwareComponents, (o1, o2) -> o1.getName().compareTo(o2.getName()));
|
Arrays.sort(softwareComponents, (o1, o2) -> o1.getName().compareTo(o2.getName()));
|
||||||
}
|
}
|
||||||
@@ -66,8 +75,10 @@ public class LicenseFragment extends Fragment {
|
|||||||
final ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
|
final ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
|
||||||
|
|
||||||
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
||||||
licenseLink.setOnClickListener(v ->
|
licenseLink.setOnClickListener(v -> {
|
||||||
showLicense(getActivity(), StandardLicenses.GPL3));
|
activeLicense = StandardLicenses.GPL3;
|
||||||
|
showLicense(getActivity(), StandardLicenses.GPL3);
|
||||||
|
});
|
||||||
|
|
||||||
for (final SoftwareComponent component : softwareComponents) {
|
for (final SoftwareComponent component : softwareComponents) {
|
||||||
final View componentView = inflater
|
final View componentView = inflater
|
||||||
@@ -81,11 +92,16 @@ public class LicenseFragment extends Fragment {
|
|||||||
component.getLicense().getAbbreviation()));
|
component.getLicense().getAbbreviation()));
|
||||||
|
|
||||||
componentView.setTag(component);
|
componentView.setTag(component);
|
||||||
componentView.setOnClickListener(v ->
|
componentView.setOnClickListener(v -> {
|
||||||
showLicense(getActivity(), component.getLicense()));
|
activeLicense = component.getLicense();
|
||||||
|
showLicense(getActivity(), component.getLicense());
|
||||||
|
});
|
||||||
softwareComponentsView.addView(componentView);
|
softwareComponentsView.addView(componentView);
|
||||||
registerForContextMenu(componentView);
|
registerForContextMenu(componentView);
|
||||||
}
|
}
|
||||||
|
if (activeLicense != null) {
|
||||||
|
showLicense(getActivity(), activeLicense);
|
||||||
|
}
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +117,7 @@ public class LicenseFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(final MenuItem item) {
|
public boolean onContextItemSelected(@NonNull final MenuItem item) {
|
||||||
// item.getMenuInfo() is null so we use the tag of the view
|
// item.getMenuInfo() is null so we use the tag of the view
|
||||||
final SoftwareComponent component = componentForContextMenu;
|
final SoftwareComponent component = componentForContextMenu;
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
@@ -116,4 +132,12 @@ public class LicenseFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||||
|
super.onSaveInstanceState(savedInstanceState);
|
||||||
|
if (activeLicense != null) {
|
||||||
|
savedInstanceState.putSerializable(LICENSE_KEY, activeLicense);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -51,7 +51,7 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
|||||||
// split the HTML file and insert the stylesheet into the HEAD of the file
|
// split the HTML file and insert the stylesheet into the HEAD of the file
|
||||||
webViewData = licenseContent.toString().replace("</head>",
|
webViewData = licenseContent.toString().replace("</head>",
|
||||||
"<style>" + getLicenseStylesheet(context) + "</style></head>");
|
"<style>" + getLicenseStylesheet(context) + "</style></head>");
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Could not get license file: " + license.getFilename(), e);
|
"Could not get license file: " + license.getFilename(), e);
|
||||||
}
|
}
|
||||||
|
@@ -14,13 +14,13 @@ import io.reactivex.Flowable;
|
|||||||
@Dao
|
@Dao
|
||||||
public interface BasicDAO<Entity> {
|
public interface BasicDAO<Entity> {
|
||||||
/* Inserts */
|
/* Inserts */
|
||||||
@Insert(onConflict = OnConflictStrategy.FAIL)
|
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||||
long insert(Entity entity);
|
long insert(Entity entity);
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.FAIL)
|
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||||
List<Long> insertAll(Entity... entities);
|
List<Long> insertAll(Entity... entities);
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.FAIL)
|
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||||
List<Long> insertAll(Collection<Entity> entities);
|
List<Long> insertAll(Collection<Entity> entities);
|
||||||
|
|
||||||
/* Searches */
|
/* Searches */
|
||||||
|
@@ -49,7 +49,7 @@ public final class Converters {
|
|||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
public static FeedGroupIcon feedGroupIconOf(final Integer id) {
|
public static FeedGroupIcon feedGroupIconOf(final Integer id) {
|
||||||
for (FeedGroupIcon icon : FeedGroupIcon.values()) {
|
for (final FeedGroupIcon icon : FeedGroupIcon.values()) {
|
||||||
if (icon.getId() == id) {
|
if (icon.getId() == id) {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.room.migration.Migration;
|
import androidx.room.migration.Migration;
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
|
||||||
public final class Migrations {
|
public final class Migrations {
|
||||||
public static final int DB_VER_1 = 1;
|
public static final int DB_VER_1 = 1;
|
||||||
@@ -14,7 +14,7 @@ public final class Migrations {
|
|||||||
public static final int DB_VER_3 = 3;
|
public static final int DB_VER_3 = 3;
|
||||||
|
|
||||||
private static final String TAG = Migrations.class.getName();
|
private static final String TAG = Migrations.class.getName();
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
|
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -50,7 +50,7 @@ public class SubscriptionEntity {
|
|||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public static SubscriptionEntity from(@NonNull final ChannelInfo info) {
|
public static SubscriptionEntity from(@NonNull final ChannelInfo info) {
|
||||||
SubscriptionEntity result = new SubscriptionEntity();
|
final SubscriptionEntity result = new SubscriptionEntity();
|
||||||
result.setServiceId(info.getServiceId());
|
result.setServiceId(info.getServiceId());
|
||||||
result.setUrl(info.getUrl());
|
result.setUrl(info.getUrl());
|
||||||
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(),
|
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(),
|
||||||
@@ -124,7 +124,7 @@ public class SubscriptionEntity {
|
|||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public ChannelInfoItem toChannelInfoItem() {
|
public ChannelInfoItem toChannelInfoItem() {
|
||||||
ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
||||||
item.setThumbnailUrl(getAvatarUrl());
|
item.setThumbnailUrl(getAvatarUrl());
|
||||||
item.setSubscriberCount(getSubscriberCount());
|
item.setSubscriberCount(getSubscriberCount());
|
||||||
item.setDescription(getDescription());
|
item.setDescription(getDescription());
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package org.schabi.newpipe.download;
|
package org.schabi.newpipe.download;
|
||||||
|
|
||||||
import android.app.FragmentTransaction;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -11,9 +10,10 @@ import android.view.ViewTreeObserver;
|
|||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.AndroidTvUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import org.schabi.newpipe.views.FocusOverlayView;
|
import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
// Service
|
// Service
|
||||||
Intent i = new Intent();
|
final Intent i = new Intent();
|
||||||
i.setClass(this, DownloadManagerService.class);
|
i.setClass(this, DownloadManagerService.class);
|
||||||
startService(i);
|
startService(i);
|
||||||
|
|
||||||
@@ -38,10 +38,10 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_downloader);
|
setContentView(R.layout.activity_downloader);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setTitle(R.string.downloads_title);
|
actionBar.setTitle(R.string.downloads_title);
|
||||||
@@ -57,13 +57,13 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (AndroidTvUtils.isTv(this)) {
|
if (DeviceUtils.isTv(this)) {
|
||||||
FocusOverlayView.setupFocusObserver(this);
|
FocusOverlayView.setupFocusObserver(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFragments() {
|
private void updateFragments() {
|
||||||
MissionsFragment fragment = new MissionsFragment();
|
final MissionsFragment fragment = new MissionsFragment();
|
||||||
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
||||||
@@ -74,7 +74,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
MenuInflater inflater = getMenuInflater();
|
final MenuInflater inflater = getMenuInflater();
|
||||||
|
|
||||||
inflater.inflate(R.menu.download_menu, menu);
|
inflater.inflate(R.menu.download_menu, menu);
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -124,7 +124,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
public static DownloadDialog newInstance(final StreamInfo info) {
|
public static DownloadDialog newInstance(final StreamInfo info) {
|
||||||
DownloadDialog dialog = new DownloadDialog();
|
final DownloadDialog dialog = new DownloadDialog();
|
||||||
dialog.setInfo(info);
|
dialog.setInfo(info);
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
@@ -208,14 +208,15 @@ public class DownloadDialog extends DialogFragment
|
|||||||
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
||||||
Icepick.restoreInstanceState(this, savedInstanceState);
|
Icepick.restoreInstanceState(this, savedInstanceState);
|
||||||
|
|
||||||
SparseArray<SecondaryStreamHelper<AudioStream>> secondaryStreams = new SparseArray<>(4);
|
final SparseArray<SecondaryStreamHelper<AudioStream>> secondaryStreams
|
||||||
List<VideoStream> videoStreams = wrappedVideoStreams.getStreamsList();
|
= new SparseArray<>(4);
|
||||||
|
final List<VideoStream> videoStreams = wrappedVideoStreams.getStreamsList();
|
||||||
|
|
||||||
for (int i = 0; i < videoStreams.size(); i++) {
|
for (int i = 0; i < videoStreams.size(); i++) {
|
||||||
if (!videoStreams.get(i).isVideoOnly()) {
|
if (!videoStreams.get(i).isVideoOnly()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AudioStream audioStream = SecondaryStreamHelper
|
final AudioStream audioStream = SecondaryStreamHelper
|
||||||
.getAudioStreamFor(wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
|
.getAudioStreamFor(wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
|
||||||
|
|
||||||
if (audioStream != null) {
|
if (audioStream != null) {
|
||||||
@@ -232,13 +233,13 @@ public class DownloadDialog extends DialogFragment
|
|||||||
this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams);
|
this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams);
|
||||||
this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams);
|
this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams);
|
||||||
|
|
||||||
Intent intent = new Intent(context, DownloadManagerService.class);
|
final Intent intent = new Intent(context, DownloadManagerService.class);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
|
|
||||||
context.bindService(intent, new ServiceConnection() {
|
context.bindService(intent, new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(final ComponentName cname, final IBinder service) {
|
public void onServiceConnected(final ComponentName cname, final IBinder service) {
|
||||||
DownloadManagerBinder mgr = (DownloadManagerBinder) service;
|
final DownloadManagerBinder mgr = (DownloadManagerBinder) service;
|
||||||
|
|
||||||
mainStorageAudio = mgr.getMainStorageAudio();
|
mainStorageAudio = mgr.getMainStorageAudio();
|
||||||
mainStorageVideo = mgr.getMainStorageVideo();
|
mainStorageVideo = mgr.getMainStorageVideo();
|
||||||
@@ -294,9 +295,9 @@ public class DownloadDialog extends DialogFragment
|
|||||||
initToolbar(view.findViewById(R.id.toolbar));
|
initToolbar(view.findViewById(R.id.toolbar));
|
||||||
setupDownloadOptions();
|
setupDownloadOptions();
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
|
|
||||||
int threads = prefs.getInt(getString(R.string.default_download_threads), 3);
|
final int threads = prefs.getInt(getString(R.string.default_download_threads), 3);
|
||||||
threadsCountTextView.setText(String.valueOf(threads));
|
threadsCountTextView.setText(String.valueOf(threads));
|
||||||
threadsSeekBar.setProgress(threads - 1);
|
threadsSeekBar.setProgress(threads - 1);
|
||||||
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
@@ -373,13 +374,13 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
||||||
File file = Utils.getFileForUri(data.getData());
|
final File file = Utils.getFileForUri(data.getData());
|
||||||
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
||||||
StoredFileHelper.DEFAULT_MIME);
|
StoredFileHelper.DEFAULT_MIME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
final DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
showFailedDialog(R.string.general_error);
|
showFailedDialog(R.string.general_error);
|
||||||
return;
|
return;
|
||||||
@@ -515,7 +516,23 @@ public class DownloadDialog extends DialogFragment
|
|||||||
videoButton.setVisibility(isVideoStreamsAvailable ? View.VISIBLE : View.GONE);
|
videoButton.setVisibility(isVideoStreamsAvailable ? View.VISIBLE : View.GONE);
|
||||||
subtitleButton.setVisibility(isSubtitleStreamsAvailable ? View.VISIBLE : View.GONE);
|
subtitleButton.setVisibility(isSubtitleStreamsAvailable ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (isVideoStreamsAvailable) {
|
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
final String defaultMedia = prefs.getString(getString(R.string.last_used_download_type),
|
||||||
|
getString(R.string.last_download_type_video_key));
|
||||||
|
|
||||||
|
if (isVideoStreamsAvailable
|
||||||
|
&& (defaultMedia.equals(getString(R.string.last_download_type_video_key)))) {
|
||||||
|
videoButton.setChecked(true);
|
||||||
|
setupVideoSpinner();
|
||||||
|
} else if (isAudioStreamsAvailable
|
||||||
|
&& (defaultMedia.equals(getString(R.string.last_download_type_audio_key)))) {
|
||||||
|
audioButton.setChecked(true);
|
||||||
|
setupAudioSpinner();
|
||||||
|
} else if (isSubtitleStreamsAvailable
|
||||||
|
&& (defaultMedia.equals(getString(R.string.last_download_type_subtitle_key)))) {
|
||||||
|
subtitleButton.setChecked(true);
|
||||||
|
setupSubtitleSpinner();
|
||||||
|
} else if (isVideoStreamsAvailable) {
|
||||||
videoButton.setChecked(true);
|
videoButton.setChecked(true);
|
||||||
setupVideoSpinner();
|
setupVideoSpinner();
|
||||||
} else if (isAudioStreamsAvailable) {
|
} else if (isAudioStreamsAvailable) {
|
||||||
@@ -564,7 +581,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getNameEditText() {
|
private String getNameEditText() {
|
||||||
String str = nameEditText.getText().toString().trim();
|
final String str = nameEditText.getText().toString().trim();
|
||||||
|
|
||||||
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
||||||
}
|
}
|
||||||
@@ -591,9 +608,10 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void prepareSelectedDownload() {
|
private void prepareSelectedDownload() {
|
||||||
StoredDirectoryHelper mainStorage;
|
final StoredDirectoryHelper mainStorage;
|
||||||
MediaFormat format;
|
final MediaFormat format;
|
||||||
String mime;
|
final String mime;
|
||||||
|
final String selectedMediaType;
|
||||||
|
|
||||||
// first, build the filename and get the output folder (if possible)
|
// first, build the filename and get the output folder (if possible)
|
||||||
// later, run a very very very large file checking logic
|
// later, run a very very very large file checking logic
|
||||||
@@ -602,6 +620,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
|
|
||||||
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
|
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
|
||||||
case R.id.audio_button:
|
case R.id.audio_button:
|
||||||
|
selectedMediaType = getString(R.string.last_download_type_audio_key);
|
||||||
mainStorage = mainStorageAudio;
|
mainStorage = mainStorageAudio;
|
||||||
format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat();
|
format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat();
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@@ -616,12 +635,14 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.video_button:
|
case R.id.video_button:
|
||||||
|
selectedMediaType = getString(R.string.last_download_type_video_key);
|
||||||
mainStorage = mainStorageVideo;
|
mainStorage = mainStorageVideo;
|
||||||
format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat();
|
format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat();
|
||||||
mime = format.mimeType;
|
mime = format.mimeType;
|
||||||
filename += format.suffix;
|
filename += format.suffix;
|
||||||
break;
|
break;
|
||||||
case R.id.subtitle_button:
|
case R.id.subtitle_button:
|
||||||
|
selectedMediaType = getString(R.string.last_download_type_subtitle_key);
|
||||||
mainStorage = mainStorageVideo; // subtitle & video files go together
|
mainStorage = mainStorageVideo; // subtitle & video files go together
|
||||||
format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat();
|
format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat();
|
||||||
mime = format.mimeType;
|
mime = format.mimeType;
|
||||||
@@ -663,6 +684,11 @@ public class DownloadDialog extends DialogFragment
|
|||||||
|
|
||||||
// check for existing file with the same name
|
// check for existing file with the same name
|
||||||
checkSelectedDownload(mainStorage, mainStorage.findFile(filename), filename, mime);
|
checkSelectedDownload(mainStorage, mainStorage.findFile(filename), filename, mime);
|
||||||
|
|
||||||
|
// remember the last media type downloaded by the user
|
||||||
|
prefs.edit()
|
||||||
|
.putString(getString(R.string.last_used_download_type), selectedMediaType)
|
||||||
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSelectedDownload(final StoredDirectoryHelper mainStorage,
|
private void checkSelectedDownload(final StoredDirectoryHelper mainStorage,
|
||||||
@@ -683,15 +709,17 @@ public class DownloadDialog extends DialogFragment
|
|||||||
storage = new StoredFileHelper(context, mainStorage.getUri(), targetFile,
|
storage = new StoredFileHelper(context, mainStorage.getUri(), targetFile,
|
||||||
mainStorage.getTag());
|
mainStorage.getTag());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
showErrorActivity(e);
|
showErrorActivity(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if is our file
|
// check if is our file
|
||||||
MissionState state = downloadManager.checkForExistingMission(storage);
|
final MissionState state = downloadManager.checkForExistingMission(storage);
|
||||||
@StringRes int msgBtn;
|
@StringRes
|
||||||
@StringRes int msgBody;
|
final int msgBtn;
|
||||||
|
@StringRes
|
||||||
|
final int msgBody;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case Finished:
|
case Finished:
|
||||||
@@ -744,8 +772,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final AlertDialog.Builder askDialog = new AlertDialog.Builder(context)
|
||||||
AlertDialog.Builder askDialog = new AlertDialog.Builder(context)
|
|
||||||
.setTitle(R.string.download_dialog_title)
|
.setTitle(R.string.download_dialog_title)
|
||||||
.setMessage(msgBody)
|
.setMessage(msgBody)
|
||||||
.setNegativeButton(android.R.string.cancel, null);
|
.setNegativeButton(android.R.string.cancel, null);
|
||||||
@@ -787,7 +814,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
// try take (or steal) the file
|
// try take (or steal) the file
|
||||||
storageNew = new StoredFileHelper(context, mainStorage.getUri(),
|
storageNew = new StoredFileHelper(context, mainStorage.getUri(),
|
||||||
targetFile, mainStorage.getTag());
|
targetFile, mainStorage.getTag());
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "Failed to take (or steal) the file in "
|
Log.e(TAG, "Failed to take (or steal) the file in "
|
||||||
+ targetFile.toString());
|
+ targetFile.toString());
|
||||||
storageNew = null;
|
storageNew = null;
|
||||||
@@ -825,18 +852,18 @@ public class DownloadDialog extends DialogFragment
|
|||||||
if (storage.length() > 0) {
|
if (storage.length() > 0) {
|
||||||
storage.truncate();
|
storage.truncate();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "failed to truncate the file: " + storage.getUri().toString(), e);
|
Log.e(TAG, "failed to truncate the file: " + storage.getUri().toString(), e);
|
||||||
showFailedDialog(R.string.overwrite_failed);
|
showFailedDialog(R.string.overwrite_failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream selectedStream;
|
final Stream selectedStream;
|
||||||
Stream secondaryStream = null;
|
Stream secondaryStream = null;
|
||||||
char kind;
|
final char kind;
|
||||||
int threads = threadsSeekBar.getProgress() + 1;
|
int threads = threadsSeekBar.getProgress() + 1;
|
||||||
String[] urls;
|
final String[] urls;
|
||||||
MissionRecoveryInfo[] recoveryInfo;
|
final MissionRecoveryInfo[] recoveryInfo;
|
||||||
String psName = null;
|
String psName = null;
|
||||||
String[] psArgs = null;
|
String[] psArgs = null;
|
||||||
long nearLength = 0;
|
long nearLength = 0;
|
||||||
@@ -857,7 +884,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
kind = 'v';
|
kind = 'v';
|
||||||
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
||||||
|
|
||||||
SecondaryStreamHelper<AudioStream> secondary = videoStreamsAdapter
|
final SecondaryStreamHelper<AudioStream> secondary = videoStreamsAdapter
|
||||||
.getAllSecondary()
|
.getAllSecondary()
|
||||||
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
||||||
|
|
||||||
@@ -871,7 +898,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
psArgs = null;
|
psArgs = null;
|
||||||
long videoSize = wrappedVideoStreams
|
final long videoSize = wrappedVideoStreams
|
||||||
.getSizeInBytes((VideoStream) selectedStream);
|
.getSizeInBytes((VideoStream) selectedStream);
|
||||||
|
|
||||||
// set nearLength, only, if both sizes are fetched or known. This probably
|
// set nearLength, only, if both sizes are fetched or known. This probably
|
||||||
|
@@ -230,7 +230,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
|||||||
}
|
}
|
||||||
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
||||||
// Starting ReCaptcha Challenge Activity
|
// Starting ReCaptcha Challenge Activity
|
||||||
Intent intent = new Intent(activity, ReCaptchaActivity.class);
|
final Intent intent = new Intent(activity, ReCaptchaActivity.class);
|
||||||
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl());
|
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl());
|
||||||
startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST);
|
startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST);
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ package org.schabi.newpipe.fragments;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -74,7 +74,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
|
|
||||||
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
|
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
|
||||||
previousYoutubeRestrictedModeEnabled =
|
previousYoutubeRestrictedModeEnabled =
|
||||||
PreferenceManager.getDefaultSharedPreferences(getContext())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +104,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
boolean youtubeRestrictedModeEnabled =
|
final boolean youtubeRestrictedModeEnabled =
|
||||||
PreferenceManager.getDefaultSharedPreferences(getContext())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
||||||
if (previousYoutubeRestrictedModeEnabled != youtubeRestrictedModeEnabled) {
|
if (previousYoutubeRestrictedModeEnabled != youtubeRestrictedModeEnabled) {
|
||||||
previousYoutubeRestrictedModeEnabled = youtubeRestrictedModeEnabled;
|
previousYoutubeRestrictedModeEnabled = youtubeRestrictedModeEnabled;
|
||||||
@@ -137,7 +137,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
}
|
}
|
||||||
inflater.inflate(R.menu.main_fragment_menu, menu);
|
inflater.inflate(R.menu.main_fragment_menu, menu);
|
||||||
|
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -148,11 +148,9 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_search:
|
case R.id.action_search:
|
||||||
try {
|
try {
|
||||||
NavigationHelper.openSearchFragment(
|
NavigationHelper.openSearchFragment(getFM(),
|
||||||
getFragmentManager(),
|
ServiceHelper.getSelectedServiceId(activity), "");
|
||||||
ServiceHelper.getSelectedServiceId(activity),
|
} catch (final Exception e) {
|
||||||
"");
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -239,7 +237,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
Fragment fragment = null;
|
Fragment fragment = null;
|
||||||
try {
|
try {
|
||||||
fragment = tab.getFragment(context);
|
fragment = tab.getFragment(context);
|
||||||
} catch (ExtractionException e) {
|
} catch (final ExtractionException e) {
|
||||||
throwable = e;
|
throwable = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,9 +14,9 @@ public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollLi
|
|||||||
super.onScrolled(recyclerView, dx, dy);
|
super.onScrolled(recyclerView, dx, dy);
|
||||||
if (dy > 0) {
|
if (dy > 0) {
|
||||||
int pastVisibleItems = 0;
|
int pastVisibleItems = 0;
|
||||||
int visibleItemCount;
|
final int visibleItemCount;
|
||||||
int totalItemCount;
|
final int totalItemCount;
|
||||||
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
||||||
|
|
||||||
visibleItemCount = layoutManager.getChildCount();
|
visibleItemCount = layoutManager.getChildCount();
|
||||||
totalItemCount = layoutManager.getItemCount();
|
totalItemCount = layoutManager.getItemCount();
|
||||||
@@ -26,7 +26,7 @@ public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollLi
|
|||||||
pastVisibleItems = ((LinearLayoutManager) layoutManager)
|
pastVisibleItems = ((LinearLayoutManager) layoutManager)
|
||||||
.findFirstVisibleItemPosition();
|
.findFirstVisibleItemPosition();
|
||||||
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
||||||
int[] positions = ((StaggeredGridLayoutManager) layoutManager)
|
final int[] positions = ((StaggeredGridLayoutManager) layoutManager)
|
||||||
.findFirstVisibleItemPositions(null);
|
.findFirstVisibleItemPositions(null);
|
||||||
if (positions != null && positions.length > 0) {
|
if (positions != null && positions.length > 0) {
|
||||||
pastVisibleItems = positions[0];
|
pastVisibleItems = positions[0];
|
||||||
|
@@ -1,16 +1,29 @@
|
|||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
class StackItem implements Serializable {
|
class StackItem implements Serializable {
|
||||||
private final int serviceId;
|
private final int serviceId;
|
||||||
private final String url;
|
private String url;
|
||||||
private String title;
|
private String title;
|
||||||
|
private PlayQueue playQueue;
|
||||||
|
|
||||||
StackItem(final int serviceId, final String url, final String title) {
|
StackItem(final int serviceId, final String url,
|
||||||
|
final String title, final PlayQueue playQueue) {
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.playQueue = playQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(final String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayQueue(final PlayQueue queue) {
|
||||||
|
this.playQueue = queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getServiceId() {
|
public int getServiceId() {
|
||||||
@@ -29,6 +42,10 @@ class StackItem implements Serializable {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlayQueue getPlayQueue() {
|
||||||
|
return playQueue;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getServiceId() + ":" + getUrl() + " > " + getTitle();
|
return getServiceId() + ":" + getUrl() + " > " + getTitle();
|
||||||
|
@@ -2,6 +2,7 @@ package org.schabi.newpipe.fragments.detail;
|
|||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
@@ -10,16 +11,20 @@ import androidx.fragment.app.FragmentPagerAdapter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TabAdaptor extends FragmentPagerAdapter {
|
public class TabAdapter extends FragmentPagerAdapter {
|
||||||
private final List<Fragment> mFragmentList = new ArrayList<>();
|
private final List<Fragment> mFragmentList = new ArrayList<>();
|
||||||
private final List<String> mFragmentTitleList = new ArrayList<>();
|
private final List<String> mFragmentTitleList = new ArrayList<>();
|
||||||
private final FragmentManager fragmentManager;
|
private final FragmentManager fragmentManager;
|
||||||
|
|
||||||
public TabAdaptor(final FragmentManager fm) {
|
public TabAdapter(final FragmentManager fm) {
|
||||||
super(fm);
|
// if changed to BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT => crash if enqueueing stream in
|
||||||
|
// the background and then clicking on it to open VideoDetailFragment:
|
||||||
|
// "Cannot setMaxLifecycle for Fragment not attached to FragmentManager"
|
||||||
|
super(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
|
||||||
this.fragmentManager = fm;
|
this.fragmentManager = fm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Fragment getItem(final int position) {
|
public Fragment getItem(final int position) {
|
||||||
return mFragmentList.get(position);
|
return mFragmentList.get(position);
|
||||||
@@ -50,14 +55,14 @@ public class TabAdaptor extends FragmentPagerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateItem(final String title, final Fragment fragment) {
|
public void updateItem(final String title, final Fragment fragment) {
|
||||||
int index = mFragmentTitleList.indexOf(title);
|
final int index = mFragmentTitleList.indexOf(title);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
updateItem(index, fragment);
|
updateItem(index, fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemPosition(final Object object) {
|
public int getItemPosition(@NonNull final Object object) {
|
||||||
if (mFragmentList.contains(object)) {
|
if (mFragmentList.contains(object)) {
|
||||||
return mFragmentList.indexOf(object);
|
return mFragmentList.indexOf(object);
|
||||||
} else {
|
} else {
|
||||||
@@ -82,7 +87,9 @@ public class TabAdaptor extends FragmentPagerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyItem(final ViewGroup container, final int position, final Object object) {
|
public void destroyItem(@NonNull final ViewGroup container,
|
||||||
|
final int position,
|
||||||
|
@NonNull final Object object) {
|
||||||
fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
|
fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user