mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-09-24 08:40:51 +02:00
Compare commits
583 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1aed11c156 | ||
![]() |
e99e944ac3 | ||
![]() |
6e523d37ba | ||
![]() |
2aebf6b522 | ||
![]() |
3f740980a3 | ||
![]() |
66b73d1592 | ||
![]() |
be4b03b84b | ||
![]() |
3594037efe | ||
![]() |
38c5cb50fb | ||
![]() |
3767a96e0f | ||
![]() |
937a387f4e | ||
![]() |
cd65f1dffc | ||
![]() |
d4e6856cbe | ||
![]() |
f61d779108 | ||
![]() |
b8b22d4d91 | ||
![]() |
25d0e39736 | ||
![]() |
79a9497e65 | ||
![]() |
c55dcccb1e | ||
![]() |
820e606719 | ||
![]() |
96291a8522 | ||
![]() |
e7b52bd3b0 | ||
![]() |
dd3251c08d | ||
![]() |
f4aabdd9b8 | ||
![]() |
cb1fe5f017 | ||
![]() |
83837bde11 | ||
![]() |
05189dadbf | ||
![]() |
dbb1f371b3 | ||
![]() |
5cc1bbc4bb | ||
![]() |
53796043c3 | ||
![]() |
a5ac528c02 | ||
![]() |
54eb353d0d | ||
![]() |
3391067cab | ||
![]() |
b4f595eb75 | ||
![]() |
58bc0c17d0 | ||
![]() |
4385404ad6 | ||
![]() |
61aadcffd2 | ||
![]() |
f575826394 | ||
![]() |
389959dd18 | ||
![]() |
af4734eee3 | ||
![]() |
f76b37ec39 | ||
![]() |
379149fe2f | ||
![]() |
3bd477631c | ||
![]() |
72c0987bad | ||
![]() |
5bba8e02a6 | ||
![]() |
b270de3335 | ||
![]() |
e22bcf0ac5 | ||
![]() |
c1d55d828f | ||
![]() |
da77970328 | ||
![]() |
32f3caaee0 | ||
![]() |
8bbacb1d78 | ||
![]() |
5904510410 | ||
![]() |
e16624251b | ||
![]() |
389f22a0e5 | ||
![]() |
7b91aa16b6 | ||
![]() |
89ec688632 | ||
![]() |
fdd0d586c9 | ||
![]() |
6f5604791f | ||
![]() |
eb9fba4147 | ||
![]() |
afb62f729f | ||
![]() |
1ccc23dc9c | ||
![]() |
7ea5cb9c5c | ||
![]() |
c301d6e5d5 | ||
![]() |
44ad69b94d | ||
![]() |
d14515ab88 | ||
![]() |
01875b389d | ||
![]() |
5eef116aaa | ||
![]() |
442220debc | ||
![]() |
4914caad51 | ||
![]() |
08cab863f1 | ||
![]() |
02458d4fc1 | ||
![]() |
6ed4130b66 | ||
![]() |
5f7ee15d1e | ||
![]() |
43afd5a2b8 | ||
![]() |
f9ac199c1f | ||
![]() |
920c169d55 | ||
![]() |
76ba2824a2 | ||
![]() |
ca0d594547 | ||
![]() |
44b6d900f0 | ||
![]() |
3b2c0186aa | ||
![]() |
efa605700d | ||
![]() |
cac360d37b | ||
![]() |
75e28893fb | ||
![]() |
360a44b5a0 | ||
![]() |
2b89e24a4b | ||
![]() |
931f34d2fd | ||
![]() |
abfdcea4db | ||
![]() |
80b3b8ac0f | ||
![]() |
60e18aa045 | ||
![]() |
85e2b124ab | ||
![]() |
81a8cd0641 | ||
![]() |
303805755d | ||
![]() |
38837d6424 | ||
![]() |
8a582c2a24 | ||
![]() |
5cfb65002d | ||
![]() |
fa6dee45ec | ||
![]() |
af25fe93da | ||
![]() |
395ad3e8ef | ||
![]() |
2cbaca8968 | ||
![]() |
bf90788e04 | ||
![]() |
83ffb849cd | ||
![]() |
a34a33e419 | ||
![]() |
57f620485f | ||
![]() |
18cdde963b | ||
![]() |
6c1f472de3 | ||
![]() |
efd2ac353e | ||
![]() |
863bf9dc8b | ||
![]() |
fd411c17cd | ||
![]() |
5424c23d69 | ||
![]() |
b8a0801786 | ||
![]() |
39ff1cd898 | ||
![]() |
a2a3b0575d | ||
![]() |
2b8954353d | ||
![]() |
9bd5aa0da4 | ||
![]() |
af2cddee91 | ||
![]() |
27bc414616 | ||
![]() |
14eaedd73a | ||
![]() |
a2effef346 | ||
![]() |
caf938f79f | ||
![]() |
8ececc11d2 | ||
![]() |
cf1d546683 | ||
![]() |
e8144f4906 | ||
![]() |
bfb6f14769 | ||
![]() |
ff1ba2b5bf | ||
![]() |
8c26f29f94 | ||
![]() |
bdd57f3b3e | ||
![]() |
e09bf4d09c | ||
![]() |
e0dbf4c2cd | ||
![]() |
4bba84af8a | ||
![]() |
bd7077c1cf | ||
![]() |
a63128bd45 | ||
![]() |
6944f4a68a | ||
![]() |
54ab0ab17e | ||
![]() |
2080bb2da1 | ||
![]() |
cc74c98509 | ||
![]() |
dd6c6ae03f | ||
![]() |
4f8ca9ef16 | ||
![]() |
53059bcb91 | ||
![]() |
cb056f4f80 | ||
![]() |
05bfa8b85e | ||
![]() |
6dc5350c43 | ||
![]() |
5cdf807d92 | ||
![]() |
9c2a9e64c2 | ||
![]() |
3b60b801c2 | ||
![]() |
c78eb80686 | ||
![]() |
9b9da648c9 | ||
![]() |
adc2b9c43a | ||
![]() |
b3954e9acd | ||
![]() |
6e36f0ef83 | ||
![]() |
64afb907e6 | ||
![]() |
3552125075 | ||
![]() |
2601bf6d81 | ||
![]() |
3da032b7ee | ||
![]() |
7bea94144e | ||
![]() |
40b08a593f | ||
![]() |
5d06e8310d | ||
![]() |
1ab82dfa32 | ||
![]() |
b93372926a | ||
![]() |
557bcc40ef | ||
![]() |
06e2e548be | ||
![]() |
7a25588995 | ||
![]() |
8107337566 | ||
![]() |
d6de11f54c | ||
![]() |
2f2334eac4 | ||
![]() |
3a5b9203d8 | ||
![]() |
c46ce1170c | ||
![]() |
1170c508b4 | ||
![]() |
f34cacbc5c | ||
![]() |
4164195fae | ||
![]() |
c03b106118 | ||
![]() |
c760a4e0ef | ||
![]() |
f3a73ecc4a | ||
![]() |
6beb36f92f | ||
![]() |
033a4ecbe8 | ||
![]() |
6360d61721 | ||
![]() |
5dd3f6cd02 | ||
![]() |
cb3c595d2b | ||
![]() |
f4414851be | ||
![]() |
9a0f61e60b | ||
![]() |
22fc690c65 | ||
![]() |
c5583bd77b | ||
![]() |
8fbee92255 | ||
![]() |
1fd6685b3b | ||
![]() |
e6fe1d2008 | ||
![]() |
c0ce14dba5 | ||
![]() |
9f315fb021 | ||
![]() |
dc46b3f6c0 | ||
![]() |
24dd94fba3 | ||
![]() |
d3d4e8c721 | ||
![]() |
990d3fc714 | ||
![]() |
9c82f0b12a | ||
![]() |
47bdd2e565 | ||
![]() |
9a5e82cb1e | ||
![]() |
2ab9db3c07 | ||
![]() |
b3fdd2b0cb | ||
![]() |
bd43efd2c2 | ||
![]() |
36babcaf36 | ||
![]() |
45be3fb0e8 | ||
![]() |
c880047c4f | ||
![]() |
66e88829dd | ||
![]() |
3add3d75a1 | ||
![]() |
8644a4542a | ||
![]() |
0b6bae6ce3 | ||
![]() |
13346ab750 | ||
![]() |
f65c08431c | ||
![]() |
4cde97e65d | ||
![]() |
049b36b1b6 | ||
![]() |
faed0958b3 | ||
![]() |
3b36b7f01b | ||
![]() |
5a2b236e71 | ||
![]() |
e5db08b0a8 | ||
![]() |
e29eeb5d3d | ||
![]() |
6dac88c394 | ||
![]() |
580a0069dc | ||
![]() |
187d65ffa5 | ||
![]() |
7b0ef1824f | ||
![]() |
404017cba3 | ||
![]() |
dd2398efad | ||
![]() |
a44518a757 | ||
![]() |
83eb83025a | ||
![]() |
464a113f11 | ||
![]() |
25a776cc93 | ||
![]() |
7d19fb878d | ||
![]() |
f5aef6879a | ||
![]() |
29014d7b4a | ||
![]() |
9668a78732 | ||
![]() |
a1aafb17c9 | ||
![]() |
9883678fd9 | ||
![]() |
ba72379aa9 | ||
![]() |
3206fef865 | ||
![]() |
06b6216b9d | ||
![]() |
5458606abe | ||
![]() |
ad5cf99d9e | ||
![]() |
0445086e67 | ||
![]() |
51641dcc9a | ||
![]() |
d1e698185e | ||
![]() |
d145a3e967 | ||
![]() |
4a5190292c | ||
![]() |
1b7cece306 | ||
![]() |
181c83090d | ||
![]() |
54c32b9fe2 | ||
![]() |
9d5951765f | ||
![]() |
ddc3b47dfa | ||
![]() |
59523d6a08 | ||
![]() |
686f395158 | ||
![]() |
f7b7340b30 | ||
![]() |
9bcdad0218 | ||
![]() |
ff4601f487 | ||
![]() |
535cebde51 | ||
![]() |
ed23faa455 | ||
![]() |
0c695d721d | ||
![]() |
d7a208dcee | ||
![]() |
3eb2a26e4e | ||
![]() |
cc2d365e5a | ||
![]() |
76ac2cc58e | ||
![]() |
aee26fcffc | ||
![]() |
685eebeb56 | ||
![]() |
f23ae091cc | ||
![]() |
1421dca35f | ||
![]() |
39c2f31a22 | ||
![]() |
239ef1c238 | ||
![]() |
466ba93750 | ||
![]() |
72007a0162 | ||
![]() |
26c0445b83 | ||
![]() |
6f6c1704d4 | ||
![]() |
14aa6de422 | ||
![]() |
eeb770ffe3 | ||
![]() |
382ac3470b | ||
![]() |
3abfb08090 | ||
![]() |
b4aac839c9 | ||
![]() |
da984c23df | ||
![]() |
cab770159d | ||
![]() |
7c2ff977d8 | ||
![]() |
5bd9334f8f | ||
![]() |
c5544df64c | ||
![]() |
c85e3c07d6 | ||
![]() |
674e1c0519 | ||
![]() |
7154a1edb8 | ||
![]() |
be1252e0e6 | ||
![]() |
a4ce6c707c | ||
![]() |
affce74b84 | ||
![]() |
730de4061f | ||
![]() |
3beafa2a74 | ||
![]() |
c622923edd | ||
![]() |
6940021293 | ||
![]() |
0156a4f39e | ||
![]() |
4bae12aa55 | ||
![]() |
f08b1224c9 | ||
![]() |
477355db8f | ||
![]() |
11c89165c5 | ||
![]() |
825f28ab9a | ||
![]() |
54ff5e1dc6 | ||
![]() |
9b46418628 | ||
![]() |
04597a9faf | ||
![]() |
5b0994dc85 | ||
![]() |
7c852c69a3 | ||
![]() |
df47e94ceb | ||
![]() |
3b68004005 | ||
![]() |
5a9c327938 | ||
![]() |
3e31e9783c | ||
![]() |
46fb3639ec | ||
![]() |
a6eba57099 | ||
![]() |
c8481f961a | ||
![]() |
56329f43fb | ||
![]() |
793fbfb5be | ||
![]() |
1d8334b762 | ||
![]() |
19330ac415 | ||
![]() |
7a015a0bda | ||
![]() |
f29c422c61 | ||
![]() |
99a369f604 | ||
![]() |
c1f0fb36ac | ||
![]() |
fa0a8905f7 | ||
![]() |
4e63a3269e | ||
![]() |
0f1873e295 | ||
![]() |
23fd28afd5 | ||
![]() |
ad5a813a9a | ||
![]() |
f245eedbdf | ||
![]() |
1ce6a6e8c5 | ||
![]() |
0ea7b5526c | ||
![]() |
b41e88f8f3 | ||
![]() |
82b9e79d99 | ||
![]() |
a5383fadb1 | ||
![]() |
bd7fb9bbe4 | ||
![]() |
1ddd0a333c | ||
![]() |
084fec08a6 | ||
![]() |
2b51448b49 | ||
![]() |
f4eee83477 | ||
![]() |
cd622c9e06 | ||
![]() |
7077ebfde2 | ||
![]() |
4862fecb12 | ||
![]() |
c189933705 | ||
![]() |
9c3f7a9139 | ||
![]() |
382bf5e936 | ||
![]() |
e2fac962f3 | ||
![]() |
3071ebc0d5 | ||
![]() |
a5fc6db1fa | ||
![]() |
8060c6a775 | ||
![]() |
2a6e7f300c | ||
![]() |
98afe79eaa | ||
![]() |
a35590f9ea | ||
![]() |
f14f8c35b8 | ||
![]() |
aa5c510c99 | ||
![]() |
59f33a8def | ||
![]() |
dbb4df598c | ||
![]() |
8452f52da0 | ||
![]() |
db6613f562 | ||
![]() |
44d2775437 | ||
![]() |
a3326dc598 | ||
![]() |
0cd56ddeb8 | ||
![]() |
2a7f729e73 | ||
![]() |
18301d8f8b | ||
![]() |
8286437055 | ||
![]() |
1bef7fbbf3 | ||
![]() |
21e8318643 | ||
![]() |
381f054daf | ||
![]() |
c05d9303a9 | ||
![]() |
cca72a9e4e | ||
![]() |
d4463e5f30 | ||
![]() |
92155e2154 | ||
![]() |
287fd0bf1e | ||
![]() |
9e910d5501 | ||
![]() |
ff54b4d0c9 | ||
![]() |
af0b841bc3 | ||
![]() |
665ea85613 | ||
![]() |
de635392c6 | ||
![]() |
7814cca3d5 | ||
![]() |
6c7204eae0 | ||
![]() |
834d647011 | ||
![]() |
d872263b55 | ||
![]() |
4f8e4ca0ad | ||
![]() |
2abc9d0210 | ||
![]() |
36fb942ce6 | ||
![]() |
56476b35e3 | ||
![]() |
38b3835891 | ||
![]() |
ccf5be116a | ||
![]() |
794ae4c5da | ||
![]() |
060e744924 | ||
![]() |
de62ed772f | ||
![]() |
6a8c4a65c5 | ||
![]() |
03738aeb27 | ||
![]() |
243cb8569e | ||
![]() |
1bd660fbbe | ||
![]() |
fec80b39f0 | ||
![]() |
21768432c8 | ||
![]() |
e9b900ff28 | ||
![]() |
c57cb8fec1 | ||
![]() |
247681e3ef | ||
![]() |
2f9142419a | ||
![]() |
b84eb3df7f | ||
![]() |
4058ec2ee9 | ||
![]() |
23a9061871 | ||
![]() |
9e95ca10b2 | ||
![]() |
4c0809d3d3 | ||
![]() |
d43365f6e6 | ||
![]() |
c6ccc2b20d | ||
![]() |
31dd68be1d | ||
![]() |
1c94620c06 | ||
![]() |
82d214faa6 | ||
![]() |
04b2e3689c | ||
![]() |
f00b8a3941 | ||
![]() |
390cc9cfc9 | ||
![]() |
8259872e2d | ||
![]() |
1a3aaf86ee | ||
![]() |
cade4f932d | ||
![]() |
eb060602cd | ||
![]() |
805f046696 | ||
![]() |
35e11e43de | ||
![]() |
ba15c6dc60 | ||
![]() |
569c227a99 | ||
![]() |
8fd7599158 | ||
![]() |
19418e5dfb | ||
![]() |
f90a163ede | ||
![]() |
8fb1fd3602 | ||
![]() |
0dbf2a347f | ||
![]() |
38742fd5e8 | ||
![]() |
67ce7e0979 | ||
![]() |
21a7e52f9a | ||
![]() |
fcb445a381 | ||
![]() |
f6450d4b4d | ||
![]() |
a01d1b89b6 | ||
![]() |
0c9b6582cc | ||
![]() |
2d47daabf8 | ||
![]() |
ce20cbe435 | ||
![]() |
99e5415bfc | ||
![]() |
b2d935dd6d | ||
![]() |
eb66cc5db8 | ||
![]() |
6d6b8363a8 | ||
![]() |
bf79b02e15 | ||
![]() |
3ce7eda3eb | ||
![]() |
378e6b6547 | ||
![]() |
f63b35e2c0 | ||
![]() |
9a480cbe3e | ||
![]() |
76ca937bb8 | ||
![]() |
8a29567572 | ||
![]() |
839cd7d1c7 | ||
![]() |
0bfc7a9177 | ||
![]() |
26e11f96e0 | ||
![]() |
86c36acedc | ||
![]() |
2318ad2bde | ||
![]() |
9548dfabd6 | ||
![]() |
0c716c12d7 | ||
![]() |
08dd176753 | ||
![]() |
07086bfb3e | ||
![]() |
b1d2e64450 | ||
![]() |
d9cd928100 | ||
![]() |
37ec26c8fd | ||
![]() |
68b7d9cdff | ||
![]() |
3aecd15916 | ||
![]() |
97d76aee18 | ||
![]() |
781bf8e7ec | ||
![]() |
77b9457707 | ||
![]() |
1210ab0de0 | ||
![]() |
3c93c4714e | ||
![]() |
f90a1ede70 | ||
![]() |
028354b283 | ||
![]() |
18493a578d | ||
![]() |
1829dc79c8 | ||
![]() |
7575e8fbe3 | ||
![]() |
eed9915c12 | ||
![]() |
be71e45954 | ||
![]() |
3a7978eca0 | ||
![]() |
c37d2250d4 | ||
![]() |
45819d1cd4 | ||
![]() |
4ac36af40c | ||
![]() |
1a2840b33f | ||
![]() |
d7e75e6011 | ||
![]() |
73316b87a3 | ||
![]() |
46402691b0 | ||
![]() |
e7cef4549f | ||
![]() |
737a41f45b | ||
![]() |
045ca40a77 | ||
![]() |
b1fe197c11 | ||
![]() |
8888530ae3 | ||
![]() |
2d51c7428e | ||
![]() |
863e2a80a2 | ||
![]() |
41d17d2a47 | ||
![]() |
36934468d6 | ||
![]() |
5029ce8728 | ||
![]() |
e6ab24bcb4 | ||
![]() |
f3bd263ada | ||
![]() |
db7ab3ffce | ||
![]() |
85c3755b96 | ||
![]() |
5decd55551 | ||
![]() |
bc468b6f36 | ||
![]() |
369d9204d9 | ||
![]() |
7caf7be97e | ||
![]() |
64c423902a | ||
![]() |
27a2dee3bd | ||
![]() |
11d3aeb0dd | ||
![]() |
f54d8d318a | ||
![]() |
210f2ef452 | ||
![]() |
d0bab6183a | ||
![]() |
3441aceba3 | ||
![]() |
0908b9cd76 | ||
![]() |
67494ad4c4 | ||
![]() |
5d8f75beb4 | ||
![]() |
8e7fde99db | ||
![]() |
bfdf165584 | ||
![]() |
9427ebd489 | ||
![]() |
e4f753ae82 | ||
![]() |
f2d9d3c2d7 | ||
![]() |
04c5f31cc1 | ||
![]() |
4ea86b714e | ||
![]() |
cc0b96cba4 | ||
![]() |
9e176f8400 | ||
![]() |
7195ff349b | ||
![]() |
8048ad343e | ||
![]() |
799a27ec84 | ||
![]() |
c7c77ab20c | ||
![]() |
8fc113cc52 | ||
![]() |
c7679bec87 | ||
![]() |
3301d8b4fb | ||
![]() |
f5892093a9 | ||
![]() |
b06238ba5d | ||
![]() |
dddcc80f30 | ||
![]() |
8854c8c9d0 | ||
![]() |
d02f441eb0 | ||
![]() |
ff89dd00b6 | ||
![]() |
7041e63268 | ||
![]() |
8126fdcd15 | ||
![]() |
2d61a2f251 | ||
![]() |
7594ee9dbe | ||
![]() |
0862a38599 | ||
![]() |
bf7dc462e8 | ||
![]() |
65b6aaec8e | ||
![]() |
e08aa14eab | ||
![]() |
851028997a | ||
![]() |
a1479d04df | ||
![]() |
d12af16f46 | ||
![]() |
2edfcb78fe | ||
![]() |
3f0947fa5b | ||
![]() |
d2b808e540 | ||
![]() |
2995a7dc8f | ||
![]() |
819db0a30b | ||
![]() |
4d727245e1 | ||
![]() |
d8281aeb34 | ||
![]() |
cd0f2061b5 | ||
![]() |
96928d46ca | ||
![]() |
6d55ac2199 | ||
![]() |
80dae6ece7 | ||
![]() |
a1a12ca9f7 | ||
![]() |
5a594173fa | ||
![]() |
1e989945b9 | ||
![]() |
679bef849c | ||
![]() |
1c17be9760 | ||
![]() |
6def0e3115 | ||
![]() |
fd3436d5c0 | ||
![]() |
a94f9fd3e5 | ||
![]() |
77850464d4 | ||
![]() |
3e9edba189 | ||
![]() |
3d168542fe | ||
![]() |
0de00e26d8 | ||
![]() |
f0705c612e | ||
![]() |
648b9b5d02 | ||
![]() |
b15a0b92f9 | ||
![]() |
80482c0578 | ||
![]() |
16701923a1 | ||
![]() |
67cee06523 | ||
![]() |
685dab39af | ||
![]() |
0ff9555cc4 | ||
![]() |
4f808dd17d | ||
![]() |
69d71dac36 | ||
![]() |
4880319991 | ||
![]() |
13b9850b39 | ||
![]() |
366f645eda | ||
![]() |
dcf7190c90 | ||
![]() |
ae6647276c | ||
![]() |
460ff37f7a | ||
![]() |
e7ef913416 | ||
![]() |
c149050a3a | ||
![]() |
a4e5ca54db | ||
![]() |
cb81fd3353 | ||
![]() |
3a8611ebf8 | ||
![]() |
352a883b5d | ||
![]() |
5247b22ef4 | ||
![]() |
1bf00e80b0 | ||
![]() |
6331d9b7a4 | ||
![]() |
0deb0ad851 | ||
![]() |
3b42041c4e | ||
![]() |
d8987aa94a | ||
![]() |
19ed16efc6 | ||
![]() |
0e32d70aef | ||
![]() |
5b71f279fd | ||
![]() |
6d170ffb16 |
36
.github/CONTRIBUTING.md
vendored
Normal file
36
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
NewPipe contribution guidelines
|
||||||
|
===============================
|
||||||
|
|
||||||
|
READ THIS GUIDELINES CAREFULLY BEFORE CONTRIBUTING.
|
||||||
|
|
||||||
|
## Crash reporting
|
||||||
|
|
||||||
|
Do not report crashes in the GitHub issue tracker. NewPipe has an automated crash report system that will ask you to send a report if a crash occures.
|
||||||
|
|
||||||
|
## Issue reporting/feature request
|
||||||
|
|
||||||
|
* Search the [existing issues](https://github.com/theScrabi/NewPipe/issues) first to make sure your issue/feature hasn't been reported/requested before
|
||||||
|
* Check if this issue/feature is already fixed/implemented in the repository
|
||||||
|
* If you are an android/java developer you are always welcome to fix/implement an issue/a feature yourself
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
|
||||||
|
* NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/)
|
||||||
|
|
||||||
|
## Code contribution
|
||||||
|
|
||||||
|
* Stick to NewPipe style guidelines (just look the other code and than do it the same way :) )
|
||||||
|
* Do not bring nonfree software/binary blobs into the project (keep it google free)
|
||||||
|
* Stick to [f-droid contribution guidelines](https://f-droid.org/wiki/page/Inclusion_Policy)
|
||||||
|
* Make changes on a separate branch, not on the master branch (Feature-branching)
|
||||||
|
* When submitting changes, you agree that your code will be licensed under GPLv3
|
||||||
|
* Please test (compile and run) your code before you submit changes!!!
|
||||||
|
* Try to figure out you selves why CI fails, or why a merge request collides
|
||||||
|
* Please maintain your code after you contributed it.
|
||||||
|
* Respond yourselves if someone request changes or notifies issues
|
||||||
|
|
||||||
|
## Communication
|
||||||
|
|
||||||
|
* I hereby declare our Slack channel as dead!!! There are no plans on building a new chat, but if there is interest on creating one and keeping it alive, I'd be pleased to create one again.
|
||||||
|
* If you want to get in contact with me or one of our other contributors you can send me an email at tnp(at)schabi.org
|
||||||
|
* Feel free to post suggestions, changes, ideas etc!
|
2
.github/ISSUE_TEMPLATE.md
vendored
Normal file
2
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- [ ] I carefully read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.
|
||||||
|
- [ ] I checked if the issue/feature exists in the latest version.
|
1
.github/PULL_REQUEST_TEAMPLATE.md
vendored
Normal file
1
.github/PULL_REQUEST_TEAMPLATE.md
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[ ] I carefully reed the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.
|
16
.travis.yml
16
.travis.yml
@@ -1,16 +1,19 @@
|
|||||||
language: android
|
language: android
|
||||||
|
jdk:
|
||||||
|
- oraclejdk8
|
||||||
android:
|
android:
|
||||||
components:
|
components:
|
||||||
# The BuildTools version used by NewPipe
|
# The BuildTools version used by NewPipe
|
||||||
- tools
|
- tools
|
||||||
- build-tools-23.0.2
|
- build-tools-23.0.3
|
||||||
|
|
||||||
# The SDK version used to compile NewPipe
|
# The SDK version used to compile NewPipe
|
||||||
- android-23
|
- android-25
|
||||||
|
|
||||||
# Additional components
|
# Additional components
|
||||||
- extra-android-support
|
- extra-android-support
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
|
- extra-google-m2repository
|
||||||
|
|
||||||
# Emulators
|
# Emulators
|
||||||
- sys-img-armeabi-v7a-android-21
|
- sys-img-armeabi-v7a-android-21
|
||||||
@@ -20,11 +23,18 @@ android:
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
||||||
|
- GRADLE_OPTS=-Xmx512m # give gradle more memory since it seem to fail otherwise
|
||||||
matrix:
|
matrix:
|
||||||
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
|
- ANDROID_TARGET=android-21 ANDROID_ABI=armeabi-v7a
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
|
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
|
||||||
- emulator -avd test -no-skin -no-audio -no-window &
|
- emulator -avd test -no-skin -no-audio -no-window &
|
||||||
- android-wait-for-emulator
|
- android-wait-for-emulator
|
||||||
- adb shell input keyevent 82 &
|
- adb shell input keyevent 82 &
|
||||||
|
|
||||||
|
script: ./gradlew --info build connectedCheck
|
||||||
|
|
||||||
|
licenses:
|
||||||
|
- '.+'
|
||||||
|
|
||||||
|
@@ -1,33 +0,0 @@
|
|||||||
#Contribution
|
|
||||||
|
|
||||||
This document contains guidelines on making contributions to NewPipe.
|
|
||||||
|
|
||||||
## Programming
|
|
||||||
|
|
||||||
* Follow the [Google Style Guidelines](https://google.github.io/styleguide/javaguide.html)
|
|
||||||
* Make a new feature on a separate branch, not on the master branch
|
|
||||||
* Make a [pull request](https://github.com/theScrabi/NewPipe/pulls) if you're done with your changes
|
|
||||||
* When submitting changes, you agree that your code will be GPLv3 licensed
|
|
||||||
|
|
||||||
## Commit messages
|
|
||||||
|
|
||||||
* The subject line of your commit message shouldn't be longer than 72 characters
|
|
||||||
* Try to keep each line of your commit message 72 characters to ensure proper
|
|
||||||
compatibility with all git tools
|
|
||||||
* [This guide](http://chris.beams.io/posts/git-commit/) goes more in depth on what makes a good commit message
|
|
||||||
|
|
||||||
## Translation
|
|
||||||
|
|
||||||
* NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/)
|
|
||||||
|
|
||||||
## Issue reporting
|
|
||||||
|
|
||||||
* Search the [existing issues](https://github.com/theScrabi/NewPipe/issues) first to make sure your issue hasn't been reported before
|
|
||||||
* Check if this issue is already fixed in the repository
|
|
||||||
* When making bug reports, be sure to tell which version of NewPipe you are using and the steps to reproduce the problem
|
|
||||||
* Please include a log if you can
|
|
||||||
|
|
||||||
## Communication
|
|
||||||
|
|
||||||
* For the time being, [Slack](http://invite.chschtsch.ml/) is being used for project communication
|
|
||||||
* Feel free to post suggestions, changes, ideas etc!
|
|
27
README.md
27
README.md
@@ -1,15 +1,21 @@
|
|||||||
|
WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
|
||||||
|
|
||||||
# NewPipe
|
# NewPipe
|
||||||
NewPipe: A free lightweight Youtube frontend for Android.
|
NewPipe: A free lightweight Youtube frontend for Android.
|
||||||
|
|
||||||
[](http://dasochan.nl/newpipe/)
|
[](https://newpipe.schabi.org)
|
||||||
|
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
||||||
|
|
||||||
|
|
||||||
Project status:
|
Project status:
|
||||||
[](https://hosted.weblate.org/engage/NewPipe/)
|
[](https://hosted.weblate.org/engage/NewPipe/)
|
||||||
[](https://travis-ci.org/theScrabi/NewPipe)
|
[](https://travis-ci.org/TeamNewPipe/NewPipe)
|
||||||
|
|
||||||
## Get NewPipe
|
## Donate
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
`16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh`
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
@@ -30,24 +36,25 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Watch YouTube videos
|
* Watch YouTube videos
|
||||||
* Listen to YouTube videos (experimental)
|
* Listen to YouTube videos (experimental)
|
||||||
* Select the streaming player to watch the video with
|
* Select the streaming player to watch the video with
|
||||||
* Download videos (experimental)
|
* Download videos
|
||||||
* Download audio only (experimental)
|
* Download audio only
|
||||||
* Open a video in Kodi
|
* Open a video in Kodi
|
||||||
* Show Next/Related videos
|
* Show Next/Related videos
|
||||||
* Search YouTube in a specific language
|
* Search YouTube in a specific language
|
||||||
* Orbot/Tor support (no streaming yet, experimental)
|
* Watch age restricted material
|
||||||
|
* Display general information about channels
|
||||||
|
|
||||||
### Coming Features
|
### Coming Features
|
||||||
|
|
||||||
* Improved Downloading
|
* Orbot/Tor support
|
||||||
* Bookmarks
|
* Bookmarks
|
||||||
* View history
|
* View history
|
||||||
* Search history
|
* Search history
|
||||||
* Search channels
|
* Search channels
|
||||||
* Display general information about channels
|
|
||||||
* Subscribe to channels
|
* Subscribe to channels
|
||||||
* Watch videos from a channel
|
* Watch videos from a channel
|
||||||
* Search/Watch Playlists
|
* Search/Watch Playlists
|
||||||
|
* Queeing videos
|
||||||
* ... and many more
|
* ... and many more
|
||||||
|
|
||||||
### Multiservice support
|
### Multiservice support
|
||||||
@@ -57,7 +64,7 @@ Although NewPipe only supports YouTube at the moment, it's designed to support m
|
|||||||
Whether you have ideas, translation, design changes, code cleaning, or real heavy code changes, help is always welcome.
|
Whether you have ideas, translation, design changes, code cleaning, or real heavy code changes, help is always welcome.
|
||||||
The more is done the better it gets!
|
The more is done the better it gets!
|
||||||
|
|
||||||
If you'd like to get involved, check our [contribution notes](CONTRIBUTING.md).
|
If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
[](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 25
|
||||||
buildToolsVersion '23.0.2'
|
buildToolsVersion '23.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 23
|
targetSdkVersion 25
|
||||||
versionCode 13
|
versionCode 20
|
||||||
versionName "0.7.4"
|
versionName "0.8.6"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -31,15 +31,20 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
testCompile 'junit:junit:4.12'
|
||||||
compile 'com.android.support:appcompat-v7:23.1.1'
|
compile 'com.android.support:appcompat-v7:25.0.0'
|
||||||
compile 'com.android.support:support-v4:23.1.1'
|
compile 'com.android.support:support-v4:25.0.0'
|
||||||
compile 'com.android.support:design:23.1.1'
|
compile 'com.android.support:design:25.0.0'
|
||||||
compile 'com.android.support:recyclerview-v7:23.1.1'
|
compile 'com.android.support:recyclerview-v7:25.0.0'
|
||||||
compile 'org.jsoup:jsoup:1.8.3'
|
compile 'org.jsoup:jsoup:1.8.3'
|
||||||
compile 'org.mozilla:rhino:1.7.7'
|
compile 'org.mozilla:rhino:1.7.7'
|
||||||
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
||||||
compile 'de.hdodenhof:circleimageview:2.0.0'
|
compile 'de.hdodenhof:circleimageview:2.0.0'
|
||||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||||
compile 'com.github.nirhart:parallaxscroll:1.0'
|
compile 'com.github.nirhart:parallaxscroll:1.0'
|
||||||
|
compile 'com.google.android.exoplayer:exoplayer:r1.5.5'
|
||||||
|
compile 'com.google.code.gson:gson:2.4'
|
||||||
|
compile 'com.nononsenseapps:filepicker:3.0.0'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
compile 'ch.acra:acra:4.9.0'
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 12.09.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeSearchEngineTest.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class YoutubeChannelExtractorTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
ChannelExtractor extractor;
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
.getChannelExtractorInstance("https://www.youtube.com/channel/UCYJ61XIK64sp6ZFFS8sctxw", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDownloader() throws Exception {
|
||||||
|
assertNotNull(NewPipe.getDownloader());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetChannelName() throws Exception {
|
||||||
|
assertEquals(extractor.getChannelName(), "Gronkh");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAvatarUrl() throws Exception {
|
||||||
|
assertTrue(extractor.getAvatarUrl(), extractor.getAvatarUrl().contains("yt3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetBannerurl() throws Exception {
|
||||||
|
assertTrue(extractor.getBannerUrl(), extractor.getBannerUrl().contains("yt3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetFeedUrl() throws Exception {
|
||||||
|
assertTrue(extractor.getFeedUrl(), extractor.getFeedUrl().contains("feed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetStreams() throws Exception {
|
||||||
|
assertTrue("no streams are received", !extractor.getStreams().getItemList().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetStreamsErrors() throws Exception {
|
||||||
|
assertTrue("errors during stream list extraction", extractor.getStreams().getErrors().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHasNextPage() throws Exception {
|
||||||
|
// this particular example (link) has a next page !!!
|
||||||
|
assertTrue("no next page link found", extractor.hasNextPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetNextPage() throws Exception {
|
||||||
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
.getChannelExtractorInstance("https://www.youtube.com/channel/UCYJ61XIK64sp6ZFFS8sctxw", 1);
|
||||||
|
assertTrue("next page didn't have content", !extractor.getStreams().getItemList().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetNextNextPageUrl() throws Exception {
|
||||||
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
.getChannelExtractorInstance("https://www.youtube.com/channel/UCYJ61XIK64sp6ZFFS8sctxw", 2);
|
||||||
|
assertTrue("next page didn't have content", extractor.hasNextPage());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||||
|
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 29.12.15.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeSearchEngineTest.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class YoutubeSearchEngineTest extends AndroidTestCase {
|
||||||
|
private SearchResult result;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
SearchEngine engine = NewPipe.getService("Youtube").getSearchEngineInstance();
|
||||||
|
|
||||||
|
result = engine.search("this is something boring", 0, "de").getSearchResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testResultList() {
|
||||||
|
assertFalse(result.resultList.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testResultErrors() {
|
||||||
|
assertTrue(result.errors == null || result.errors.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSuggestion() {
|
||||||
|
//todo write a real test
|
||||||
|
assertTrue(result.suggestion != null);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.search.SuggestionExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeSuggestionExtractor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 18.11.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeSearchResultTest.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class YoutubeSearchResultTest extends AndroidTestCase {
|
||||||
|
List<String> suggestionReply;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
SuggestionExtractor engine = new YoutubeSuggestionExtractor(0);
|
||||||
|
suggestionReply = engine.suggestionList("hello", "de");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIfSuggestions() {
|
||||||
|
assertFalse(suggestionReply.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
@@ -1,17 +1,19 @@
|
|||||||
package org.schabi.newpipe.services.youtube;
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.Downloader;
|
||||||
import org.schabi.newpipe.crawler.CrawlingException;
|
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
||||||
import org.schabi.newpipe.crawler.ParsingException;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.crawler.services.youtube.YoutubeStreamExtractor;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.crawler.VideoInfo;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by the-scrabi on 30.12.15.
|
* Created by Christian Schabesberger on 30.12.15.
|
||||||
*
|
*
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
* YoutubeVideoExtractorDefault.java is part of NewPipe.
|
* YoutubeVideoExtractorDefault.java is part of NewPipe.
|
||||||
@@ -31,15 +33,14 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||||
private YoutubeStreamExtractor extractor;
|
public static final String HTTPS = "https://";
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
public void setUp() throws IOException, CrawlingException {
|
public void setUp() throws Exception {
|
||||||
/* some anonymus video test
|
super.setUp();
|
||||||
extractor = new YoutubeStreamExtractor("https://www.youtube.com/watch?v=FmG385_uUys",
|
NewPipe.init(Downloader.getInstance());
|
||||||
new Downloader()); */
|
extractor = NewPipe.getService("Youtube")
|
||||||
/* some vevo video (suggested to test against) */
|
.getExtractorInstance("https://www.youtube.com/watch?v=YQHsXMglC9A");
|
||||||
extractor = new YoutubeStreamExtractor("https://www.youtube.com/watch?v=YQHsXMglC9A",
|
|
||||||
new Downloader());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetInvalidTimeStamp() throws ParsingException {
|
public void testGetInvalidTimeStamp() throws ParsingException {
|
||||||
@@ -47,9 +48,10 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
|||||||
extractor.getTimeStamp() <= 0);
|
extractor.getTimeStamp() <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetValidTimeStamp() throws CrawlingException, IOException {
|
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||||
YoutubeStreamExtractor extractor =
|
StreamExtractor extractor =
|
||||||
new YoutubeStreamExtractor("https://youtu.be/FmG385_uUys?t=174", new Downloader());
|
NewPipe.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174");
|
||||||
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
extractor.getTimeStamp() == 174);
|
extractor.getTimeStamp() == 174);
|
||||||
}
|
}
|
||||||
@@ -70,22 +72,27 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
|||||||
assertTrue(extractor.getLength() > 0);
|
assertTrue(extractor.getLength() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetViews() throws ParsingException {
|
public void testGetViewCount() throws ParsingException {
|
||||||
assertTrue(extractor.getLength() > 0);
|
assertTrue(Long.toString(extractor.getViewCount()),
|
||||||
|
extractor.getViewCount() > /* specific to that video */ 1224000074);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetUploadDate() throws ParsingException {
|
public void testGetUploadDate() throws ParsingException {
|
||||||
assertTrue(extractor.getUploadDate().length() > 0);
|
assertTrue(extractor.getUploadDate().length() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetChannelUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getChannelUrl().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetThumbnailUrl() throws ParsingException {
|
public void testGetThumbnailUrl() throws ParsingException {
|
||||||
assertTrue(extractor.getThumbnailUrl(),
|
assertTrue(extractor.getThumbnailUrl(),
|
||||||
extractor.getThumbnailUrl().contains("https://"));
|
extractor.getThumbnailUrl().contains(HTTPS));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||||
assertTrue(extractor.getUploaderThumbnailUrl(),
|
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||||
extractor.getUploaderThumbnailUrl().contains("https://"));
|
extractor.getUploaderThumbnailUrl().contains(HTTPS));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetAudioStreams() throws ParsingException {
|
public void testGetAudioStreams() throws ParsingException {
|
||||||
@@ -93,17 +100,21 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testGetVideoStreams() throws ParsingException {
|
public void testGetVideoStreams() throws ParsingException {
|
||||||
for(VideoInfo.VideoStream s : extractor.getVideoStreams()) {
|
for(VideoStream s : extractor.getVideoStreams()) {
|
||||||
assertTrue(s.url,
|
assertTrue(s.url,
|
||||||
s.url.contains("https://"));
|
s.url.contains(HTTPS));
|
||||||
assertTrue(s.resolution.length() > 0);
|
assertTrue(s.resolution.length() > 0);
|
||||||
assertTrue(Integer.toString(s.format),
|
assertTrue(Integer.toString(s.format),
|
||||||
0 <= s.format && s.format <= 4);
|
0 <= s.format && s.format <= 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testStreamType() throws ParsingException {
|
||||||
|
assertTrue(extractor.getStreamType() == AbstractStreamInfo.StreamType.VIDEO_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetDashMpd() throws ParsingException {
|
public void testGetDashMpd() throws ParsingException {
|
||||||
assertTrue(extractor.getDashMpdUrl(),
|
assertTrue(extractor.getDashMpdUrl(),
|
||||||
!extractor.getDashMpdUrl().isEmpty());
|
extractor.getDashMpdUrl() != null || !extractor.getDashMpdUrl().isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,15 +1,16 @@
|
|||||||
package org.schabi.newpipe.services.youtube;
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.Downloader;
|
||||||
import org.schabi.newpipe.crawler.CrawlingException;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.crawler.services.youtube.YoutubeStreamExtractor;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by the-scrabi on 30.12.15.
|
* Created by Christian Schabesberger on 30.12.15.
|
||||||
*
|
*
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
* YoutubeVideoExtractorGema.java is part of NewPipe.
|
* YoutubeVideoExtractorGema.java is part of NewPipe.
|
||||||
@@ -35,12 +36,12 @@ public class YoutubeStreamExtractorGemaTest extends AndroidTestCase {
|
|||||||
// Deaktivate this Test Case bevore uploading it githup, otherwise CI will fail.
|
// Deaktivate this Test Case bevore uploading it githup, otherwise CI will fail.
|
||||||
private static final boolean testActive = false;
|
private static final boolean testActive = false;
|
||||||
|
|
||||||
public void testGemaError() throws IOException, CrawlingException {
|
public void testGemaError() throws IOException, ExtractionException {
|
||||||
if(testActive) {
|
if(testActive) {
|
||||||
try {
|
try {
|
||||||
new YoutubeStreamExtractor("https://www.youtube.com/watch?v=3O1_3zBUKM8",
|
NewPipe.init(Downloader.getInstance());
|
||||||
new Downloader());
|
NewPipe.getService("Youtube")
|
||||||
assertTrue("Gema exception not thrown", false);
|
.getExtractorInstance("https://www.youtube.com/watch?v=3O1_3zBUKM8");
|
||||||
} catch(YoutubeStreamExtractor.GemaException ge) {
|
} catch(YoutubeStreamExtractor.GemaException ge) {
|
||||||
assertTrue(true);
|
assertTrue(true);
|
||||||
}
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 11.03.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeStreamExtractorLiveStreamTest.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class YoutubeStreamExtractorLiveStreamTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
|
public void setUp() throws IOException, ExtractionException {
|
||||||
|
//todo: make the extractor not throw over a livestream
|
||||||
|
/*
|
||||||
|
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=J0s6NjqdjLE", Downloader.getInstance());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStreamType() throws ParsingException {
|
||||||
|
assertTrue(true);
|
||||||
|
// assertTrue(extractor.getStreamType() == AbstractVideoInfo.StreamType.LIVE_STREAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,89 @@
|
|||||||
|
package org.schabi.newpipe.extractor.youtube;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class YoutubeStreamExtractorRestrictedTest extends AndroidTestCase {
|
||||||
|
public static final String HTTPS = "https://";
|
||||||
|
private StreamExtractor extractor;
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://www.youtube.com/watch?v=i6JTvzrpBy0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetInvalidTimeStamp() throws ParsingException {
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||||
|
StreamExtractor extractor= NewPipe.getService("Youtube")
|
||||||
|
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174");
|
||||||
|
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||||
|
extractor.getTimeStamp() == 174);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAgeLimit() throws ParsingException {
|
||||||
|
assertTrue(extractor.getAgeLimit() == 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetTitle() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getTitle().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDescription() throws ParsingException {
|
||||||
|
assertTrue(extractor.getDescription() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploader() throws ParsingException {
|
||||||
|
assertTrue(!extractor.getUploader().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetLength() throws ParsingException {
|
||||||
|
assertTrue(extractor.getLength() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetViews() throws ParsingException {
|
||||||
|
assertTrue(extractor.getLength() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploadDate() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploadDate().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getThumbnailUrl(),
|
||||||
|
extractor.getThumbnailUrl().contains(HTTPS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||||
|
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||||
|
extractor.getUploaderThumbnailUrl().contains(HTTPS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAudioStreams() throws ParsingException {
|
||||||
|
// audiostream not always necessary
|
||||||
|
//assertTrue(!extractor.getAudioStreams().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetVideoStreams() throws ParsingException {
|
||||||
|
for(VideoStream s : extractor.getVideoStreams()) {
|
||||||
|
assertTrue(s.url,
|
||||||
|
s.url.contains(HTTPS));
|
||||||
|
assertTrue(s.resolution.length() > 0);
|
||||||
|
assertTrue(Integer.toString(s.format),
|
||||||
|
0 <= s.format && s.format <= 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,93 +0,0 @@
|
|||||||
package org.schabi.newpipe.services.youtube;
|
|
||||||
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.crawler.VideoPreviewInfo;
|
|
||||||
import org.schabi.newpipe.crawler.SearchEngine;
|
|
||||||
import org.schabi.newpipe.crawler.services.youtube.YoutubeSearchEngine;
|
|
||||||
import org.schabi.newpipe.Downloader;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by the-scrabi on 29.12.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* YoutubeSearchEngineTest.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class YoutubeSearchEngineTest extends AndroidTestCase {
|
|
||||||
private SearchEngine.Result result;
|
|
||||||
private ArrayList<String> suggestionReply;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception{
|
|
||||||
super.setUp();
|
|
||||||
SearchEngine engine = new YoutubeSearchEngine();
|
|
||||||
|
|
||||||
result = engine.search("https://www.youtube.com/results?search_query=bla",
|
|
||||||
0, "de", new Downloader());
|
|
||||||
suggestionReply = engine.suggestionList("hello", new Downloader());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfNoErrorOccur() {
|
|
||||||
assertEquals(result.errorMessage, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfListIsNotEmpty() {
|
|
||||||
assertEquals(result.resultList.size() > 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testItemsHaveTitle() {
|
|
||||||
for(VideoPreviewInfo i : result.resultList) {
|
|
||||||
assertEquals(i.title.isEmpty(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testItemsHaveUploader() {
|
|
||||||
for(VideoPreviewInfo i : result.resultList) {
|
|
||||||
assertEquals(i.uploader.isEmpty(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testItemsHaveRightDuration() {
|
|
||||||
for(VideoPreviewInfo i : result.resultList) {
|
|
||||||
assertTrue(i.duration, i.duration.contains(":"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testItemsHaveRightThumbnail() {
|
|
||||||
for (VideoPreviewInfo i : result.resultList) {
|
|
||||||
assertTrue(i.thumbnail_url, i.thumbnail_url.contains("https://"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testItemsHaveRightVideoUrl() {
|
|
||||||
for (VideoPreviewInfo i : result.resultList) {
|
|
||||||
assertTrue(i.webpage_url, i.webpage_url.contains("https://"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfSuggestionsAreReplied() {
|
|
||||||
assertEquals(suggestionReply.size() > 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIfSuggestionsAreValid() {
|
|
||||||
for(String s : suggestionReply) {
|
|
||||||
assertTrue(s, !s.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,23 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.schabi.newpipe" >
|
package="org.schabi.newpipe">
|
||||||
<uses-permission android:name= "android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name= "android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:logo="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:logo="@mipmap/ic_launcher"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".VideoItemListActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name">
|
||||||
android:configChanges="orientation|screenSize">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
@@ -25,14 +27,13 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".VideoItemDetailActivity"
|
android:name=".detail.VideoItemDetailActivity"
|
||||||
android:label="@string/title_videoitem_detail"
|
android:label="@string/title_videoitem_detail"
|
||||||
android:theme="@style/AppTheme"
|
android:launchMode="singleTask"
|
||||||
android:configChanges="orientation|screenSize"
|
android:theme="@style/AppTheme">
|
||||||
android:screenOrientation="portrait">
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".VideoItemListActivity" />
|
android:value=".MainActivity" />
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -49,6 +50,7 @@
|
|||||||
<data android:host="www.youtube.com" />
|
<data android:host="www.youtube.com" />
|
||||||
<data android:pathPrefix="/v/" />
|
<data android:pathPrefix="/v/" />
|
||||||
<data android:pathPrefix="/watch" />
|
<data android:pathPrefix="/watch" />
|
||||||
|
<data android:pathPrefix="/attribution_link" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -74,21 +76,50 @@
|
|||||||
<data android:scheme="vnd.youtube" />
|
<data android:scheme="vnd.youtube" />
|
||||||
<data android:scheme="vnd.youtube.launch" />
|
<data android:scheme="vnd.youtube.launch" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".PlayVideoActivity"
|
<activity
|
||||||
|
android:name=".player.PlayVideoActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
android:theme="@style/VideoPlayerTheme"
|
android:theme="@style/VideoPlayerTheme"
|
||||||
android:parentActivityName=".VideoItemDetailActivity"
|
tools:ignore="UnusedAttribute" />
|
||||||
tools:ignore="UnusedAttribute">
|
|
||||||
</activity>
|
|
||||||
<service
|
<service
|
||||||
android:name=".BackgroundPlayer"
|
android:name=".player.BackgroundPlayer"
|
||||||
android:label="@string/background_player_name"
|
android:exported="false"
|
||||||
android:exported="false" />
|
android:label="@string/background_player_name" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".SettingsActivity"
|
android:name=".player.ExoPlayerActivity"
|
||||||
android:label="@string/settings_activity_title" >
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/PlayerTheme">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.schabi.newpipe.exoplayer.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:scheme="content" />
|
||||||
|
<data android:scheme="asset" />
|
||||||
|
<data android:scheme="file" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".player.BackgroundPlayer"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/background_player_name" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".settings.SettingsActivity"
|
||||||
|
android:label="@string/settings_activity_title" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".PanicResponderActivity"
|
android:name=".PanicResponderActivity"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
@@ -96,11 +127,40 @@
|
|||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="info.guardianproject.panic.action.TRIGGER" />
|
<action android:name="info.guardianproject.panic.action.TRIGGER" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ExitActivity"
|
android:name=".ExitActivity"
|
||||||
|
android:label="@string/general_error"
|
||||||
android:theme="@android:style/Theme.NoDisplay" />
|
android:theme="@android:style/Theme.NoDisplay" />
|
||||||
|
<activity android:name=".report.ErrorActivity" />
|
||||||
|
|
||||||
|
<!-- giga get related -->
|
||||||
|
<activity
|
||||||
|
android:name=".download.DownloadActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
|
<service android:name="us.shandian.giga.service.DownloadManagerService" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.nononsenseapps.filepicker.FilePickerActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/FilePickerTheme"
|
||||||
|
android:launchMode="singleTop">
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ChannelActivity"
|
||||||
|
android:label="@string/title_activity_channel"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ReCaptchaActivity"
|
||||||
|
android:label="@string/reCaptchaActivity" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
|
||||||
|
</manifest>
|
@@ -22,13 +22,15 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton:
|
* Singleton:
|
||||||
* Used to send data between certain Activity/Services within the same process.
|
* Used to send data between certain Activity/Services within the same process.
|
||||||
* This can be considered as hack inside the Android universe. **/
|
* This can be considered as an ugly hack inside the Android universe. **/
|
||||||
public class ActivityCommunicator {
|
public class ActivityCommunicator {
|
||||||
|
|
||||||
private static ActivityCommunicator activityCommunicator = null;
|
private static ActivityCommunicator activityCommunicator;
|
||||||
|
|
||||||
public static ActivityCommunicator getCommunicator() {
|
public static ActivityCommunicator getCommunicator() {
|
||||||
if(activityCommunicator == null) {
|
if(activityCommunicator == null) {
|
||||||
@@ -39,4 +41,6 @@ public class ActivityCommunicator {
|
|||||||
|
|
||||||
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
||||||
public volatile Bitmap backgroundPlayerThumbnail;
|
public volatile Bitmap backgroundPlayerThumbnail;
|
||||||
|
|
||||||
|
public volatile Class returnActivity;
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,20 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||||
|
|
||||||
|
import org.acra.ACRA;
|
||||||
|
import org.acra.config.ACRAConfiguration;
|
||||||
|
import org.acra.config.ACRAConfigurationException;
|
||||||
|
import org.acra.config.ConfigurationBuilder;
|
||||||
|
import org.acra.sender.ReportSenderFactory;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
|
||||||
import info.guardianproject.netcipher.NetCipher;
|
import info.guardianproject.netcipher.NetCipher;
|
||||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||||
|
|
||||||
@@ -30,24 +38,45 @@ import info.guardianproject.netcipher.proxy.OrbotHelper;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
|
private static final String TAG = App.class.toString();
|
||||||
|
|
||||||
private static boolean useTor;
|
private static boolean useTor;
|
||||||
|
|
||||||
|
final Class<? extends ReportSenderFactory>[] reportSenderFactoryClasses
|
||||||
|
= new Class[]{AcraReportSenderFactory.class};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
// init crashreport
|
||||||
|
try {
|
||||||
|
final ACRAConfiguration acraConfig = new ConfigurationBuilder(this)
|
||||||
|
.setReportSenderFactoryClasses(reportSenderFactoryClasses)
|
||||||
|
.build();
|
||||||
|
ACRA.init(this, acraConfig);
|
||||||
|
} catch(ACRAConfigurationException ace) {
|
||||||
|
ace.printStackTrace();
|
||||||
|
ErrorActivity.reportError(this, ace, null, null,
|
||||||
|
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,"none",
|
||||||
|
"Could not initialize ACRA crash report", R.string.app_ui_crash));
|
||||||
|
}
|
||||||
|
|
||||||
|
//init NewPipe
|
||||||
|
NewPipe.init(Downloader.getInstance());
|
||||||
|
|
||||||
// Initialize image loader
|
// Initialize image loader
|
||||||
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
|
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
|
||||||
ImageLoader.getInstance().init(config);
|
ImageLoader.getInstance().init(config);
|
||||||
|
|
||||||
|
/*
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
if(prefs.getBoolean(getString(R.string.use_tor_key), false)) {
|
if(prefs.getBoolean(getString(R.string.use_tor_key), false)) {
|
||||||
OrbotHelper.requestStartTor(this);
|
OrbotHelper.requestStartTor(this);
|
||||||
configureTor(true);
|
configureTor(true);
|
||||||
} else {
|
} else {
|
||||||
configureTor(false);
|
configureTor(false);
|
||||||
}
|
}*/
|
||||||
|
configureTor(false);
|
||||||
|
|
||||||
// DO NOT REMOVE THIS FUNCTION!!!
|
// DO NOT REMOVE THIS FUNCTION!!!
|
||||||
// Otherwise downloadPathPreference has invalid value.
|
// Otherwise downloadPathPreference has invalid value.
|
||||||
@@ -57,7 +86,7 @@ public class App extends Application {
|
|||||||
/**
|
/**
|
||||||
* Set the proxy settings based on whether Tor should be enabled or not.
|
* Set the proxy settings based on whether Tor should be enabled or not.
|
||||||
*/
|
*/
|
||||||
static void configureTor(boolean enabled) {
|
public static void configureTor(boolean enabled) {
|
||||||
useTor = enabled;
|
useTor = enabled;
|
||||||
if (useTor) {
|
if (useTor) {
|
||||||
NetCipher.useTor();
|
NetCipher.useTor();
|
||||||
@@ -66,13 +95,13 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkStartTor(Context context) {
|
public static void checkStartTor(Context context) {
|
||||||
if (useTor) {
|
if (useTor) {
|
||||||
OrbotHelper.requestStartTor(context);
|
OrbotHelper.requestStartTor(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isUsingTor() {
|
public static boolean isUsingTor() {
|
||||||
return useTor;
|
return useTor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
268
app/src/main/java/org/schabi/newpipe/ChannelActivity.java
Normal file
268
app/src/main/java/org/schabi/newpipe/ChannelActivity.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,154 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 21.09.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* DownloadDialog.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DownloadDialog extends DialogFragment {
|
|
||||||
private static final String TAG = DialogFragment.class.getName();
|
|
||||||
|
|
||||||
public static final String TITLE = "name";
|
|
||||||
public static final String FILE_SUFFIX_AUDIO = "file_suffix_audio";
|
|
||||||
public static final String FILE_SUFFIX_VIDEO = "file_suffix_video";
|
|
||||||
public static final String AUDIO_URL = "audio_url";
|
|
||||||
public static final String VIDEO_URL = "video_url";
|
|
||||||
private Bundle arguments;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
arguments = getArguments();
|
|
||||||
super.onCreateDialog(savedInstanceState);
|
|
||||||
if(ContextCompat.checkSelfPermission(this.getContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)
|
|
||||||
ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},0);
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
||||||
builder.setTitle(R.string.download_dialog_title)
|
|
||||||
.setItems(R.array.download_options, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
Context context = getActivity();
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
String suffix = "";
|
|
||||||
String title = arguments.getString(TITLE);
|
|
||||||
String url = "";
|
|
||||||
File downloadDir = NewPipeSettings.getDownloadFolder();
|
|
||||||
switch(which) {
|
|
||||||
case 0: // Video
|
|
||||||
suffix = arguments.getString(FILE_SUFFIX_VIDEO);
|
|
||||||
url = arguments.getString(VIDEO_URL);
|
|
||||||
downloadDir = NewPipeSettings.getVideoDownloadFolder(context);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
suffix = arguments.getString(FILE_SUFFIX_AUDIO);
|
|
||||||
url = arguments.getString(AUDIO_URL);
|
|
||||||
downloadDir = NewPipeSettings.getAudioDownloadFolder(context);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.d(TAG, "lolz");
|
|
||||||
}
|
|
||||||
if(!downloadDir.exists()) {
|
|
||||||
//attempt to create directory
|
|
||||||
boolean mkdir = downloadDir.mkdirs();
|
|
||||||
if(!mkdir && !downloadDir.isDirectory()) {
|
|
||||||
String message = context.getString(R.string.err_dir_create,downloadDir.toString());
|
|
||||||
Log.e(TAG, message);
|
|
||||||
Toast.makeText(context,message , Toast.LENGTH_LONG).show();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String message = context.getString(R.string.info_dir_created,downloadDir.toString());
|
|
||||||
Log.e(TAG, message);
|
|
||||||
Toast.makeText(context,message , Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
File saveFilePath = new File(downloadDir,createFileName(title) + suffix);
|
|
||||||
|
|
||||||
long id = 0;
|
|
||||||
if (App.isUsingTor()) {
|
|
||||||
// if using Tor, do not use DownloadManager because the proxy cannot be set
|
|
||||||
FileDownloader.downloadFile(getContext(), url, saveFilePath, title);
|
|
||||||
} else {
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Request request = new DownloadManager.Request(
|
|
||||||
Uri.parse(url));
|
|
||||||
request.setDestinationUri(Uri.fromFile(saveFilePath));
|
|
||||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
|
||||||
|
|
||||||
request.setTitle(title);
|
|
||||||
request.setDescription("'" + url +
|
|
||||||
"' => '" + saveFilePath + "'");
|
|
||||||
request.allowScanningByMediaScanner();
|
|
||||||
|
|
||||||
try {
|
|
||||||
id = dm.enqueue(request);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG,"Started downloading '" + url +
|
|
||||||
"' => '" + saveFilePath + "' #" + id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* #143 #44 #42 #22: make shure that the filename does not contain illegal chars.
|
|
||||||
* This should fix some of the "cannot download" problems.
|
|
||||||
* */
|
|
||||||
private String createFileName(String fName) {
|
|
||||||
// from http://eng-przemelek.blogspot.de/2009/07/how-to-create-valid-file-name.html
|
|
||||||
|
|
||||||
List<String> forbiddenCharsPatterns = new ArrayList<String> ();
|
|
||||||
forbiddenCharsPatterns.add("[:]+"); // Mac OS, but it looks that also Windows XP
|
|
||||||
forbiddenCharsPatterns.add("[\\*\"/\\\\\\[\\]\\:\\;\\|\\=\\,]+"); // Windows
|
|
||||||
forbiddenCharsPatterns.add("[^\\w\\d\\.]+"); // last chance... only latin letters and digits
|
|
||||||
String nameToTest = fName;
|
|
||||||
for (String pattern : forbiddenCharsPatterns) {
|
|
||||||
nameToTest = nameToTest.replaceAll(pattern, "_");
|
|
||||||
}
|
|
||||||
return nameToTest;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,14 +1,18 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
import info.guardianproject.netcipher.NetCipher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 28.01.16.
|
* Created by Christian Schabesberger on 28.01.16.
|
||||||
@@ -30,25 +34,65 @@ import info.guardianproject.netcipher.NetCipher;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Downloader implements org.schabi.newpipe.crawler.Downloader {
|
public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
||||||
|
|
||||||
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
|
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
|
||||||
|
private static String mCookies = "";
|
||||||
|
|
||||||
|
private static Downloader instance = null;
|
||||||
|
|
||||||
|
private Downloader() {}
|
||||||
|
|
||||||
|
public static Downloader getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
synchronized (Downloader.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new Downloader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void setCookies(String cookies) {
|
||||||
|
Downloader.mCookies = cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized String getCookies() {
|
||||||
|
return Downloader.mCookies;
|
||||||
|
}
|
||||||
|
|
||||||
/**Download the text file at the supplied URL as in download(String),
|
/**Download the text file at the supplied URL as in download(String),
|
||||||
* but set the HTTP header field "Accept-Language" to the supplied string.
|
* but set the HTTP header field "Accept-Language" to the supplied string.
|
||||||
* @param siteUrl the URL of the text file to return the contents of
|
* @param siteUrl the URL of the text file to return the contents of
|
||||||
* @param language the language (usually a 2-character code) to set as the preferred language
|
* @param language the language (usually a 2-character code) to set as the preferred language
|
||||||
* @return the contents of the specified text file*/
|
* @return the contents of the specified text file*/
|
||||||
public String download(String siteUrl, String language) throws IOException {
|
public String download(String siteUrl, String language) throws IOException, ReCaptchaException {
|
||||||
|
Map<String, String> requestProperties = new HashMap<>();
|
||||||
|
requestProperties.put("Accept-Language", language);
|
||||||
|
return download(siteUrl, requestProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**Download the text file at the supplied URL as in download(String),
|
||||||
|
* but set the HTTP header field "Accept-Language" to the supplied string.
|
||||||
|
* @param siteUrl the URL of the text file to return the contents of
|
||||||
|
* @param customProperties set request header properties
|
||||||
|
* @return the contents of the specified text file
|
||||||
|
* @throws IOException*/
|
||||||
|
public String download(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
|
||||||
URL url = new URL(siteUrl);
|
URL url = new URL(siteUrl);
|
||||||
//HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
Iterator it = customProperties.entrySet().iterator();
|
||||||
con.setRequestProperty("Accept-Language", language);
|
while(it.hasNext()) {
|
||||||
|
Map.Entry pair = (Map.Entry)it.next();
|
||||||
|
con.setRequestProperty((String)pair.getKey(), (String)pair.getValue());
|
||||||
|
}
|
||||||
return dl(con);
|
return dl(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Common functionality between download(String url) and download(String url, String language)*/
|
/**Common functionality between download(String url) and download(String url, String language)*/
|
||||||
private static String dl(HttpsURLConnection con) throws IOException {
|
private static String dl(HttpsURLConnection con) throws IOException, ReCaptchaException {
|
||||||
StringBuilder response = new StringBuilder();
|
StringBuilder response = new StringBuilder();
|
||||||
BufferedReader in = null;
|
BufferedReader in = null;
|
||||||
|
|
||||||
@@ -56,6 +100,10 @@ public class Downloader implements org.schabi.newpipe.crawler.Downloader {
|
|||||||
con.setRequestMethod("GET");
|
con.setRequestMethod("GET");
|
||||||
con.setRequestProperty("User-Agent", USER_AGENT);
|
con.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
|
if (getCookies().length() > 0) {
|
||||||
|
con.setRequestProperty("Cookie", getCookies());
|
||||||
|
}
|
||||||
|
|
||||||
in = new BufferedReader(
|
in = new BufferedReader(
|
||||||
new InputStreamReader(con.getInputStream()));
|
new InputStreamReader(con.getInputStream()));
|
||||||
String inputLine;
|
String inputLine;
|
||||||
@@ -67,6 +115,14 @@ public class Downloader implements org.schabi.newpipe.crawler.Downloader {
|
|||||||
throw new IOException("unknown host or no network", uhe);
|
throw new IOException("unknown host or no network", uhe);
|
||||||
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
/*
|
||||||
|
* HTTP 429 == Too Many Request
|
||||||
|
* Receive from Youtube.com = ReCaptcha challenge request
|
||||||
|
* See : https://github.com/rg3/youtube-dl/issues/5138
|
||||||
|
*/
|
||||||
|
if (con.getResponseCode() == 429) {
|
||||||
|
throw new ReCaptchaException("reCaptcha Challenge requested");
|
||||||
|
}
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
} finally {
|
} finally {
|
||||||
if(in != null) {
|
if(in != null) {
|
||||||
@@ -81,7 +137,7 @@ public class Downloader implements org.schabi.newpipe.crawler.Downloader {
|
|||||||
* Primarily intended for downloading web pages.
|
* Primarily intended for downloading web pages.
|
||||||
* @param siteUrl the URL of the text file to download
|
* @param siteUrl the URL of the text file to download
|
||||||
* @return the contents of the specified text file*/
|
* @return the contents of the specified text file*/
|
||||||
public String download(String siteUrl) throws IOException {
|
public String download(String siteUrl) throws IOException, ReCaptchaException {
|
||||||
URL url = new URL(siteUrl);
|
URL url = new URL(siteUrl);
|
||||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
//HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
//HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
||||||
|
@@ -0,0 +1,64 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 01.08.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* StreamInfoItemViewCreator.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ImageErrorLoadingListener implements ImageLoadingListener {
|
||||||
|
|
||||||
|
private int serviceId = -1;
|
||||||
|
private Activity activity = null;
|
||||||
|
private View rootView = null;
|
||||||
|
|
||||||
|
public ImageErrorLoadingListener(Activity activity, View rootView, int serviceId) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.serviceId= serviceId;
|
||||||
|
this.rootView = rootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingStarted(String imageUri, View view) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||||
|
ErrorActivity.reportError(activity,
|
||||||
|
failReason.getCause(), null, rootView,
|
||||||
|
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
|
||||||
|
NewPipe.getNameOfService(serviceId), imageUri,
|
||||||
|
R.string.could_not_load_image));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingCancelled(String imageUri, View view) {}
|
||||||
|
}
|
@@ -34,6 +34,9 @@ import java.util.Locale;
|
|||||||
|
|
||||||
public class Localization {
|
public class Localization {
|
||||||
|
|
||||||
|
private Localization() {
|
||||||
|
}
|
||||||
|
|
||||||
public static Locale getPreferredLocale(Context context) {
|
public static Locale getPreferredLocale(Context context) {
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
86
app/src/main/java/org/schabi/newpipe/MainActivity.java
Normal file
86
app/src/main/java/org/schabi/newpipe/MainActivity.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.NavUtils;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 02.08.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
|
* DownloadActivity.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private Fragment mainFragment = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||||
|
mainFragment = getSupportFragmentManager()
|
||||||
|
.findFragmentById(R.id.search_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
|
||||||
|
inflater.inflate(R.menu.main_menu, menu);
|
||||||
|
|
||||||
|
mainFragment.onCreateOptionsMenu(menu, inflater);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
switch(id) {
|
||||||
|
case android.R.id.home: {
|
||||||
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
NavUtils.navigateUpTo(this, intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.action_settings: {
|
||||||
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.action_show_downloads: {
|
||||||
|
Intent intent = new Intent(this, org.schabi.newpipe.download.DownloadActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return mainFragment.onOptionsItemSelected(item) ||
|
||||||
|
super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
138
app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
Normal file
138
app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.NavUtils;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.webkit.CookieManager;
|
||||||
|
import android.webkit.ValueCallback;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by beneth <bmauduit@beneth.fr> on 06.12.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* ReCaptchaActivity.java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
public class ReCaptchaActivity extends AppCompatActivity {
|
||||||
|
public static final String TAG = ReCaptchaActivity.class.toString();
|
||||||
|
public static final String YT_URL = "https://www.youtube.com";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_recaptcha);
|
||||||
|
|
||||||
|
ActionBar actionBar = getSupportActionBar();
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
actionBar.setTitle(R.string.reCaptcha_title);
|
||||||
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
|
|
||||||
|
WebView myWebView = (WebView) findViewById(R.id.reCaptchaWebView);
|
||||||
|
|
||||||
|
// Enable Javascript
|
||||||
|
WebSettings webSettings = myWebView.getSettings();
|
||||||
|
webSettings.setJavaScriptEnabled(true);
|
||||||
|
|
||||||
|
ReCaptchaWebViewClient webClient = new ReCaptchaWebViewClient(this);
|
||||||
|
myWebView.setWebViewClient(webClient);
|
||||||
|
|
||||||
|
// Cleaning cache, history and cookies from webView
|
||||||
|
myWebView.clearCache(true);
|
||||||
|
myWebView.clearHistory();
|
||||||
|
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
cookieManager.removeAllCookies(new ValueCallback<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void onReceiveValue(Boolean aBoolean) {}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cookieManager.removeAllCookie();
|
||||||
|
}
|
||||||
|
|
||||||
|
myWebView.loadUrl(YT_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReCaptchaWebViewClient extends WebViewClient {
|
||||||
|
private Activity context;
|
||||||
|
private String mCookies;
|
||||||
|
|
||||||
|
ReCaptchaWebViewClient(Activity ctx) {
|
||||||
|
context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
String cookies = CookieManager.getInstance().getCookie(url);
|
||||||
|
|
||||||
|
// find cookies : s_gl & goojf and Add cookies to Downloader
|
||||||
|
if (find_access_cookies(cookies)) {
|
||||||
|
// Give cookies to Downloader class
|
||||||
|
Downloader.setCookies(mCookies);
|
||||||
|
|
||||||
|
// Closing activity and return to parent.
|
||||||
|
Intent intent = new Intent(context, org.schabi.newpipe.MainActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
NavUtils.navigateUpTo(context, intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean find_access_cookies(String cookies) {
|
||||||
|
boolean ret = false;
|
||||||
|
String c_s_gl = "";
|
||||||
|
String c_goojf = "";
|
||||||
|
|
||||||
|
String[] parts = cookies.split("; ");
|
||||||
|
for (String part : parts) {
|
||||||
|
if (part.trim().startsWith("s_gl")) {
|
||||||
|
c_s_gl = part.trim();
|
||||||
|
}
|
||||||
|
if (part.trim().startsWith("goojf")) {
|
||||||
|
c_goojf = part.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c_s_gl.length() > 0 && c_goojf.length() > 0) {
|
||||||
|
ret = true;
|
||||||
|
//mCookies = c_s_gl + "; " + c_goojf;
|
||||||
|
// Youtube seems to also need the other cookies:
|
||||||
|
mCookies = cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
switch (id) {
|
||||||
|
case android.R.id.home: {
|
||||||
|
Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
NavUtils.navigateUpTo(this, intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,94 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.crawler.VideoPreviewInfo;
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 24.10.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* VideoInfoItemViewCreator.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class VideoInfoItemViewCreator {
|
|
||||||
private final LayoutInflater inflater;
|
|
||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
|
||||||
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
|
||||||
|
|
||||||
public VideoInfoItemViewCreator(LayoutInflater inflater) {
|
|
||||||
this.inflater = inflater;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info, Context context) {
|
|
||||||
ViewHolder holder;
|
|
||||||
if(convertView == null) {
|
|
||||||
convertView = inflater.inflate(R.layout.video_item, parent, false);
|
|
||||||
holder = new ViewHolder();
|
|
||||||
holder.itemThumbnailView = (ImageView) convertView.findViewById(R.id.itemThumbnailView);
|
|
||||||
holder.itemVideoTitleView = (TextView) convertView.findViewById(R.id.itemVideoTitleView);
|
|
||||||
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
|
|
||||||
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
|
|
||||||
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
|
|
||||||
holder.itemViewCountView = (TextView) convertView.findViewById(R.id.itemViewCountView);
|
|
||||||
convertView.setTag(holder);
|
|
||||||
} else {
|
|
||||||
holder = (ViewHolder) convertView.getTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(info.thumbnail == null) {
|
|
||||||
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
|
||||||
} else {
|
|
||||||
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
|
|
||||||
}
|
|
||||||
holder.itemVideoTitleView.setText(info.title);
|
|
||||||
holder.itemUploaderView.setText(info.uploader);
|
|
||||||
holder.itemDurationView.setText(info.duration);
|
|
||||||
holder.itemViewCountView.setText(shortViewCount(info.view_count));
|
|
||||||
if(!info.upload_date.isEmpty()) {
|
|
||||||
holder.itemUploadDateView.setText(info.upload_date+" • ");
|
|
||||||
}
|
|
||||||
|
|
||||||
imageLoader.displayImage(info.thumbnail_url, holder.itemThumbnailView, displayImageOptions);
|
|
||||||
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewHolder {
|
|
||||||
public ImageView itemThumbnailView;
|
|
||||||
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String shortViewCount(Long view_count){
|
|
||||||
if(view_count >= 1000000000){
|
|
||||||
return Long.toString(view_count/1000000000)+"B views";
|
|
||||||
}else if(view_count>=1000000){
|
|
||||||
return Long.toString(view_count/1000000)+"M views";
|
|
||||||
}else if(view_count>=1000){
|
|
||||||
return Long.toString(view_count/1000)+"K views";
|
|
||||||
}else {
|
|
||||||
return Long.toString(view_count)+" views";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,157 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v4.app.NavUtils;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.crawler.ServiceList;
|
|
||||||
import org.schabi.newpipe.crawler.StreamingService;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* VideoItemDetailActivity.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class VideoItemDetailActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
private static final String TAG = VideoItemDetailActivity.class.toString();
|
|
||||||
|
|
||||||
private VideoItemDetailFragment fragment;
|
|
||||||
|
|
||||||
private String videoUrl;
|
|
||||||
private int currentStreamingService = -1;
|
|
||||||
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_videoitem_detail);
|
|
||||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
|
||||||
// Show the Up button in the action bar.
|
|
||||||
try {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
} catch(Exception e) {
|
|
||||||
Log.d(TAG, "Could not get SupportActionBar");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// savedInstanceState is non-null when there is fragment state
|
|
||||||
// saved from previous configurations of this activity
|
|
||||||
// (e.g. when rotating the screen from portrait to landscape).
|
|
||||||
// In this case, the fragment will automatically be re-added
|
|
||||||
// to its container so we don't need to manually add it.
|
|
||||||
// For more information, see the Fragments API guide at:
|
|
||||||
//
|
|
||||||
// http://developer.android.com/guide/components/fragments.html
|
|
||||||
//
|
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
if (savedInstanceState == null) {
|
|
||||||
// this means the video was called though another app
|
|
||||||
if (getIntent().getData() != null) {
|
|
||||||
videoUrl = getIntent().getData().toString();
|
|
||||||
StreamingService[] serviceList = ServiceList.getServices();
|
|
||||||
//StreamExtractor videoExtractor = null;
|
|
||||||
for (int i = 0; i < serviceList.length; i++) {
|
|
||||||
if (serviceList[i].getUrlIdHandler().acceptUrl(videoUrl)) {
|
|
||||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
|
|
||||||
currentStreamingService = i;
|
|
||||||
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(currentStreamingService == -1) {
|
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
//arguments.putString(VideoItemDetailFragment.VIDEO_URL,
|
|
||||||
// videoExtractor.getVideoUrl(videoExtractor.getVideoId(videoUrl)));//cleans URL
|
|
||||||
arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
|
||||||
|
|
||||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getBoolean(getString(R.string.autoplay_through_intent_key), false));
|
|
||||||
} else {
|
|
||||||
videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL);
|
|
||||||
currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1);
|
|
||||||
arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
|
||||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
|
|
||||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
videoUrl = savedInstanceState.getString(VideoItemDetailFragment.VIDEO_URL);
|
|
||||||
currentStreamingService = savedInstanceState.getInt(VideoItemDetailFragment.STREAMING_SERVICE);
|
|
||||||
arguments = savedInstanceState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the detail fragment and add it to the activity
|
|
||||||
// using a fragment transaction.
|
|
||||||
fragment = new VideoItemDetailFragment();
|
|
||||||
fragment.setArguments(arguments);
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.add(R.id.videoitem_detail_container, fragment)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
App.checkStartTor(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
|
||||||
outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
|
||||||
outState.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
|
|
||||||
outState.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
int id = item.getItemId();
|
|
||||||
if (id == android.R.id.home) {
|
|
||||||
// This ID represents the Home or Up button. In the case of this
|
|
||||||
// activity, the Up button is shown. Use NavUtils to allow users
|
|
||||||
// to navigate up one level in the application structure. For
|
|
||||||
// more details, see the Navigation pattern on Android Design:
|
|
||||||
|
|
||||||
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
|
|
||||||
|
|
||||||
Intent intent = new Intent(this, VideoItemListActivity.class);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
NavUtils.navigateUpTo(this, intent);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return fragment.onOptionsItemSelected(item) ||
|
|
||||||
super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
super.onCreateOptionsMenu(menu);
|
|
||||||
fragment.onCreateOptionsMenu(menu, getMenuInflater());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.ListView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.crawler.VideoPreviewInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 11.08.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* VideoListAdapter.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class VideoListAdapter extends BaseAdapter {
|
|
||||||
private final Context context;
|
|
||||||
private final VideoInfoItemViewCreator viewCreator;
|
|
||||||
private Vector<VideoPreviewInfo> videoList = new Vector<>();
|
|
||||||
private final ListView listView;
|
|
||||||
|
|
||||||
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
|
|
||||||
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(context));
|
|
||||||
this.listView = videoListFragment.getListView();
|
|
||||||
this.listView.setDivider(null);
|
|
||||||
this.listView.setDividerHeight(0);
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addVideoList(List<VideoPreviewInfo> videos) {
|
|
||||||
videoList.addAll(videos);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearVideoList() {
|
|
||||||
videoList = new Vector<>();
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector<VideoPreviewInfo> getVideoList() {
|
|
||||||
return videoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return videoList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getItem(int position) {
|
|
||||||
return videoList.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
|
||||||
convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context);
|
|
||||||
|
|
||||||
if(listView.isItemChecked(position)) {
|
|
||||||
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.light_youtube_primary_color));
|
|
||||||
} else {
|
|
||||||
convertView.setBackgroundColor(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user