mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-09-22 10:00:55 +02:00
Compare commits
352 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 | ||
![]() |
21e8318643 |
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.
|
13
.travis.yml
13
.travis.yml
@@ -1,16 +1,19 @@
|
||||
language: android
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
android:
|
||||
components:
|
||||
# The BuildTools version used by NewPipe
|
||||
- tools
|
||||
- build-tools-23.0.2
|
||||
- build-tools-23.0.3
|
||||
|
||||
# The SDK version used to compile NewPipe
|
||||
- android-23
|
||||
- android-25
|
||||
|
||||
# Additional components
|
||||
- extra-android-support
|
||||
- extra-android-m2repository
|
||||
- extra-google-m2repository
|
||||
|
||||
# Emulators
|
||||
- sys-img-armeabi-v7a-android-21
|
||||
@@ -22,7 +25,7 @@ env:
|
||||
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
||||
- GRADLE_OPTS=-Xmx512m # give gradle more memory since it seem to fail otherwise
|
||||
matrix:
|
||||
- ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
|
||||
- ANDROID_TARGET=android-21 ANDROID_ABI=armeabi-v7a
|
||||
|
||||
before_script:
|
||||
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
|
||||
@@ -31,3 +34,7 @@ before_script:
|
||||
- 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!
|
26
README.md
26
README.md
@@ -1,22 +1,22 @@
|
||||
WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
|
||||
|
||||
# NewPipe
|
||||
NewPipe: A free lightweight Youtube frontend for Android.
|
||||
|
||||
[](https://newpipe.schabi.org)
|
||||
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
||||
|
||||
|
||||
Project status:
|
||||
[](https://hosted.weblate.org/engage/NewPipe/)
|
||||
[](https://travis-ci.org/theScrabi/NewPipe)
|
||||
|
||||
## Get NewPipe
|
||||
|
||||
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
||||
[](https://travis-ci.org/TeamNewPipe/NewPipe)
|
||||
|
||||
## Donate
|
||||

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

|
||||
|
||||
`16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh`
|
||||
|
||||
## Screenshots
|
||||
|
||||
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
|
||||
@@ -36,25 +36,25 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
||||
* Watch YouTube videos
|
||||
* Listen to YouTube videos (experimental)
|
||||
* Select the streaming player to watch the video with
|
||||
* Download videos (experimental)
|
||||
* Download audio only (experimental)
|
||||
* Download videos
|
||||
* Download audio only
|
||||
* Open a video in Kodi
|
||||
* Show Next/Related videos
|
||||
* Search YouTube in a specific language
|
||||
* Orbot/Tor support (no streaming yet, experimental)
|
||||
* Watch age restricted material
|
||||
* Display general information about channels
|
||||
|
||||
### Coming Features
|
||||
|
||||
* Improved Downloading
|
||||
* Orbot/Tor support
|
||||
* Bookmarks
|
||||
* View history
|
||||
* Search history
|
||||
* Search channels
|
||||
* Display general information about channels
|
||||
* Subscribe to channels
|
||||
* Watch videos from a channel
|
||||
* Search/Watch Playlists
|
||||
* Queeing videos
|
||||
* ... and many more
|
||||
|
||||
### Multiservice support
|
||||
@@ -64,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.
|
||||
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
|
||||
[](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
@@ -1,15 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion '23.0.2'
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '23.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.schabi.newpipe"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 17
|
||||
versionName "0.7.8"
|
||||
targetSdkVersion 25
|
||||
versionCode 20
|
||||
versionName "0.8.6"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -31,11 +31,11 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
compile 'com.android.support:appcompat-v7:23.2.0'
|
||||
compile 'com.android.support:support-v4:23.2.0'
|
||||
compile 'com.android.support:design:23.2.0'
|
||||
compile 'com.android.support:recyclerview-v7:23.2.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support:appcompat-v7:25.0.0'
|
||||
compile 'com.android.support:support-v4:25.0.0'
|
||||
compile 'com.android.support:design:25.0.0'
|
||||
compile 'com.android.support:recyclerview-v7:25.0.0'
|
||||
compile 'org.jsoup:jsoup:1.8.3'
|
||||
compile 'org.mozilla:rhino:1.7.7'
|
||||
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
||||
@@ -43,4 +43,8 @@ dependencies {
|
||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||
compile 'com.github.nirhart:parallaxscroll:1.0'
|
||||
compile 'com.google.android.exoplayer:exoplayer:r1.5.5'
|
||||
compile 'com.google.code.gson:gson:2.4'
|
||||
compile 'com.nononsenseapps:filepicker: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());
|
||||
}
|
||||
}
|
@@ -2,17 +2,12 @@ package org.schabi.newpipe.extractor.youtube;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||
import org.schabi.newpipe.extractor.SearchResult;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
||||
import org.schabi.newpipe.extractor.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeSearchEngine;
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeService;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 29.12.15.
|
||||
@@ -36,86 +31,26 @@ import java.util.ArrayList;
|
||||
|
||||
public class YoutubeSearchEngineTest extends AndroidTestCase {
|
||||
private SearchResult result;
|
||||
private ArrayList<String> suggestionReply;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception{
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
SearchEngine engine = ServiceList.getService("Youtube")
|
||||
.getSearchEngineInstance(new Downloader());
|
||||
NewPipe.init(Downloader.getInstance());
|
||||
SearchEngine engine = NewPipe.getService("Youtube").getSearchEngineInstance();
|
||||
|
||||
result = engine.search("lefloid",
|
||||
0, "de", new Downloader()).getSearchResult();
|
||||
suggestionReply = engine.suggestionList("hello","de",new Downloader());
|
||||
result = engine.search("this is something boring", 0, "de").getSearchResult();
|
||||
}
|
||||
|
||||
public void testIfNoErrorOccur() {
|
||||
assertTrue(result.errors.isEmpty() ? "" : ExceptionUtils.getStackTrace(result.errors.get(0))
|
||||
,result.errors.isEmpty());
|
||||
public void testResultList() {
|
||||
assertFalse(result.resultList.isEmpty());
|
||||
}
|
||||
|
||||
public void testIfListIsNotEmpty() {
|
||||
assertEquals(result.resultList.size() > 0, true);
|
||||
public void testResultErrors() {
|
||||
assertTrue(result.errors == null || result.errors.isEmpty());
|
||||
}
|
||||
|
||||
public void testItemsHaveTitle() {
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertEquals(i.title.isEmpty(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public void testItemsHaveUploader() {
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertEquals(i.uploader.isEmpty(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public void testItemsHaveRightDuration() {
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue(i.duration >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testItemsHaveRightThumbnail() {
|
||||
for (StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue(i.thumbnail_url, i.thumbnail_url.contains("https://"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testItemsHaveRightVideoUrl() {
|
||||
for (StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue(i.webpage_url, i.webpage_url.contains("https://"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testViewCount() {
|
||||
/*
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue(Long.toString(i.view_count), i.view_count != -1);
|
||||
}
|
||||
*/
|
||||
// that specific link used for this test, there are no videos with less
|
||||
// than 10.000 views, so we can test against that.
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue(i.title + ": " + Long.toString(i.view_count), i.view_count >= 10000);
|
||||
}
|
||||
}
|
||||
|
||||
public void testStreamType() {
|
||||
for(StreamPreviewInfo i : result.resultList) {
|
||||
assertTrue("not a livestream and not a video",
|
||||
i.stream_type == AbstractVideoInfo.StreamType.VIDEO_STREAM ||
|
||||
i.stream_type == AbstractVideoInfo.StreamType.LIVE_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
public void testIfSuggestionsAreReplied() {
|
||||
assertEquals(!suggestionReply.isEmpty(), true);
|
||||
}
|
||||
|
||||
public void testIfSuggestionsAreValid() {
|
||||
for(String s : suggestionReply) {
|
||||
assertTrue(s, !s.isEmpty());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
@@ -3,12 +3,12 @@ package org.schabi.newpipe.extractor.youtube;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.ParsingException;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||
import org.schabi.newpipe.extractor.VideoStream;
|
||||
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
||||
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;
|
||||
|
||||
@@ -33,11 +33,14 @@ import java.io.IOException;
|
||||
*/
|
||||
|
||||
public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||
public static final String HTTPS = "https://";
|
||||
private StreamExtractor extractor;
|
||||
|
||||
public void setUp() throws IOException, ExtractionException {
|
||||
extractor = ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=YQHsXMglC9A", new Downloader());
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
NewPipe.init(Downloader.getInstance());
|
||||
extractor = NewPipe.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=YQHsXMglC9A");
|
||||
}
|
||||
|
||||
public void testGetInvalidTimeStamp() throws ParsingException {
|
||||
@@ -47,8 +50,8 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||
|
||||
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||
StreamExtractor extractor =
|
||||
ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("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()),
|
||||
extractor.getTimeStamp() == 174);
|
||||
}
|
||||
@@ -78,14 +81,18 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||
assertTrue(extractor.getUploadDate().length() > 0);
|
||||
}
|
||||
|
||||
public void testGetChannelUrl() throws ParsingException {
|
||||
assertTrue(extractor.getChannelUrl().length() > 0);
|
||||
}
|
||||
|
||||
public void testGetThumbnailUrl() throws ParsingException {
|
||||
assertTrue(extractor.getThumbnailUrl(),
|
||||
extractor.getThumbnailUrl().contains("https://"));
|
||||
extractor.getThumbnailUrl().contains(HTTPS));
|
||||
}
|
||||
|
||||
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||
extractor.getUploaderThumbnailUrl().contains("https://"));
|
||||
extractor.getUploaderThumbnailUrl().contains(HTTPS));
|
||||
}
|
||||
|
||||
public void testGetAudioStreams() throws ParsingException {
|
||||
@@ -95,7 +102,7 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||
public void testGetVideoStreams() throws ParsingException {
|
||||
for(VideoStream s : extractor.getVideoStreams()) {
|
||||
assertTrue(s.url,
|
||||
s.url.contains("https://"));
|
||||
s.url.contains(HTTPS));
|
||||
assertTrue(s.resolution.length() > 0);
|
||||
assertTrue(Integer.toString(s.format),
|
||||
0 <= s.format && s.format <= 4);
|
||||
@@ -103,7 +110,7 @@ public class YoutubeStreamExtractorDefaultTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testStreamType() throws ParsingException {
|
||||
assertTrue(extractor.getStreamType() == AbstractVideoInfo.StreamType.VIDEO_STREAM);
|
||||
assertTrue(extractor.getStreamType() == AbstractStreamInfo.StreamType.VIDEO_STREAM);
|
||||
}
|
||||
|
||||
public void testGetDashMpd() throws ParsingException {
|
||||
|
@@ -3,8 +3,8 @@ package org.schabi.newpipe.extractor.youtube;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -39,9 +39,9 @@ public class YoutubeStreamExtractorGemaTest extends AndroidTestCase {
|
||||
public void testGemaError() throws IOException, ExtractionException {
|
||||
if(testActive) {
|
||||
try {
|
||||
ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=3O1_3zBUKM8",
|
||||
new Downloader());
|
||||
NewPipe.init(Downloader.getInstance());
|
||||
NewPipe.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=3O1_3zBUKM8");
|
||||
} catch(YoutubeStreamExtractor.GemaException ge) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
@@ -2,12 +2,10 @@ package org.schabi.newpipe.extractor.youtube;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.ParsingException;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -15,7 +13,7 @@ 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.
|
||||
* 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
|
||||
@@ -32,15 +30,17 @@ import java.io.IOException;
|
||||
*/
|
||||
|
||||
|
||||
public class YoutubestreamExtractorLiveStreamTest extends AndroidTestCase {
|
||||
public class YoutubeStreamExtractorLiveStreamTest extends AndroidTestCase {
|
||||
|
||||
private StreamExtractor extractor;
|
||||
|
||||
public void setUp() throws IOException, ExtractionException {
|
||||
//todo: make the extractor not throw over a livestream
|
||||
/*
|
||||
extractor = ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=J0s6NjqdjLE", new Downloader());
|
||||
|
||||
NewPipe.init(Downloader.getInstance());
|
||||
extractor = NewPipe.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=J0s6NjqdjLE", Downloader.getInstance());
|
||||
*/
|
||||
}
|
||||
|
@@ -3,21 +3,23 @@ package org.schabi.newpipe.extractor.youtube;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.ParsingException;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamExtractor;
|
||||
import org.schabi.newpipe.extractor.VideoStream;
|
||||
import 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 IOException, ExtractionException {
|
||||
extractor = ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("https://www.youtube.com/watch?v=i6JTvzrpBy0",
|
||||
new Downloader());
|
||||
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 {
|
||||
@@ -26,9 +28,8 @@ public class YoutubeStreamExtractorRestrictedTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testGetValidTimeStamp() throws ExtractionException, IOException {
|
||||
StreamExtractor extractor=ServiceList.getService("Youtube")
|
||||
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174",
|
||||
new Downloader());
|
||||
StreamExtractor extractor= NewPipe.getService("Youtube")
|
||||
.getExtractorInstance("https://youtu.be/FmG385_uUys?t=174");
|
||||
assertTrue(Integer.toString(extractor.getTimeStamp()),
|
||||
extractor.getTimeStamp() == 174);
|
||||
}
|
||||
@@ -63,22 +64,23 @@ public class YoutubeStreamExtractorRestrictedTest extends AndroidTestCase {
|
||||
|
||||
public void testGetThumbnailUrl() throws ParsingException {
|
||||
assertTrue(extractor.getThumbnailUrl(),
|
||||
extractor.getThumbnailUrl().contains("https://"));
|
||||
extractor.getThumbnailUrl().contains(HTTPS));
|
||||
}
|
||||
|
||||
public void testGetUploaderThumbnailUrl() throws ParsingException {
|
||||
assertTrue(extractor.getUploaderThumbnailUrl(),
|
||||
extractor.getUploaderThumbnailUrl().contains("https://"));
|
||||
extractor.getUploaderThumbnailUrl().contains(HTTPS));
|
||||
}
|
||||
|
||||
public void testGetAudioStreams() throws ParsingException {
|
||||
assertTrue(!extractor.getAudioStreams().isEmpty());
|
||||
// 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://"));
|
||||
s.url.contains(HTTPS));
|
||||
assertTrue(s.resolution.length() > 0);
|
||||
assertTrue(Integer.toString(s.format),
|
||||
0 <= s.format && s.format <= 4);
|
||||
|
@@ -16,8 +16,9 @@
|
||||
android:logo="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="AllowBackup">
|
||||
|
||||
<activity
|
||||
android:name=".VideoItemListActivity"
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -26,12 +27,13 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".VideoItemDetailActivity"
|
||||
android:name=".detail.VideoItemDetailActivity"
|
||||
android:label="@string/title_videoitem_detail"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".VideoItemListActivity" />
|
||||
android:value=".MainActivity" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -74,17 +76,24 @@
|
||||
<data android:scheme="vnd.youtube" />
|
||||
<data android:scheme="vnd.youtube.launch" />
|
||||
</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
|
||||
android:name=".player.PlayVideoActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/VideoPlayerTheme"
|
||||
tools:ignore="UnusedAttribute"/>
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
<service
|
||||
android:name=".player.BackgroundPlayer"
|
||||
android:exported="false"
|
||||
android:label="@string/background_player_name"/>
|
||||
<activity
|
||||
android:label="@string/background_player_name" />
|
||||
|
||||
<activity
|
||||
android:name=".player.ExoPlayerActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
@@ -102,12 +111,14 @@
|
||||
<data android:scheme="file" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".player.BackgroundPlayer"
|
||||
android:label="@string/background_player_name"
|
||||
android:exported="false" />
|
||||
android:exported="false"
|
||||
android:label="@string/background_player_name" />
|
||||
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:label="@string/settings_activity_title" />
|
||||
<activity
|
||||
android:name=".PanicResponderActivity"
|
||||
@@ -124,6 +135,32 @@
|
||||
android:name=".ExitActivity"
|
||||
android:label="@string/general_error"
|
||||
android:theme="@android:style/Theme.NoDisplay" />
|
||||
<activity android:name=".ErrorActivity"/>
|
||||
<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>
|
||||
</manifest>
|
||||
|
||||
</manifest>
|
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
* This can be considered as an ugly hack inside the Android universe. **/
|
||||
public class ActivityCommunicator {
|
||||
|
||||
private static ActivityCommunicator activityCommunicator = null;
|
||||
private static ActivityCommunicator activityCommunicator;
|
||||
|
||||
public static ActivityCommunicator getCommunicator() {
|
||||
if(activityCommunicator == null) {
|
||||
@@ -42,8 +42,5 @@ public class ActivityCommunicator {
|
||||
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
||||
public volatile Bitmap backgroundPlayerThumbnail;
|
||||
|
||||
// Sent from any activity to ErrorActivity.
|
||||
public volatile List<Exception> errorList;
|
||||
public volatile Class returnActivity;
|
||||
public volatile ErrorActivity.ErrorInfo errorInfo;
|
||||
}
|
||||
|
@@ -2,12 +2,20 @@ package org.schabi.newpipe;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||
|
||||
import 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.proxy.OrbotHelper;
|
||||
|
||||
@@ -30,24 +38,45 @@ import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||
*/
|
||||
|
||||
public class App extends Application {
|
||||
private static final String TAG = App.class.toString();
|
||||
|
||||
private static boolean useTor;
|
||||
|
||||
final Class<? extends ReportSenderFactory>[] reportSenderFactoryClasses
|
||||
= new Class[]{AcraReportSenderFactory.class};
|
||||
|
||||
@Override
|
||||
public void 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
|
||||
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
|
||||
ImageLoader.getInstance().init(config);
|
||||
|
||||
/*
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if(prefs.getBoolean(getString(R.string.use_tor_key), false)) {
|
||||
OrbotHelper.requestStartTor(this);
|
||||
configureTor(true);
|
||||
} else {
|
||||
configureTor(false);
|
||||
}
|
||||
}*/
|
||||
configureTor(false);
|
||||
|
||||
// DO NOT REMOVE THIS FUNCTION!!!
|
||||
// Otherwise downloadPathPreference has invalid value.
|
||||
|
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,14 +1,18 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 28.01.16.
|
||||
@@ -33,22 +37,62 @@ import info.guardianproject.netcipher.NetCipher;
|
||||
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 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),
|
||||
* 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 language the language (usually a 2-character code) to set as the preferred language
|
||||
* @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);
|
||||
//HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
HttpsURLConnection con = NetCipher.getHttpsURLConnection(url);
|
||||
con.setRequestProperty("Accept-Language", language);
|
||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
Iterator it = customProperties.entrySet().iterator();
|
||||
while(it.hasNext()) {
|
||||
Map.Entry pair = (Map.Entry)it.next();
|
||||
con.setRequestProperty((String)pair.getKey(), (String)pair.getValue());
|
||||
}
|
||||
return dl(con);
|
||||
}
|
||||
|
||||
/**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();
|
||||
BufferedReader in = null;
|
||||
|
||||
@@ -56,6 +100,10 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
||||
con.setRequestMethod("GET");
|
||||
con.setRequestProperty("User-Agent", USER_AGENT);
|
||||
|
||||
if (getCookies().length() > 0) {
|
||||
con.setRequestProperty("Cookie", getCookies());
|
||||
}
|
||||
|
||||
in = new BufferedReader(
|
||||
new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
@@ -67,6 +115,14 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
||||
throw new IOException("unknown host or no network", uhe);
|
||||
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
||||
} 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);
|
||||
} finally {
|
||||
if(in != null) {
|
||||
@@ -81,7 +137,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
||||
* Primarily intended for downloading web pages.
|
||||
* @param siteUrl the URL of the text file to download
|
||||
* @return the contents of the specified text file*/
|
||||
public String download(String siteUrl) throws IOException {
|
||||
public String download(String siteUrl) throws IOException, ReCaptchaException {
|
||||
URL url = new URL(siteUrl);
|
||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
//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) {}
|
||||
}
|
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,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.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.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].getUrlIdHandlerInstance().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
@@ -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.extractor.StreamPreviewInfo;
|
||||
|
||||
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<StreamPreviewInfo> 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<StreamPreviewInfo> videos) {
|
||||
videoList.addAll(videos);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clearVideoList() {
|
||||
videoList = new Vector<>();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public Vector<StreamPreviewInfo> 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));
|
||||
|
||||
if(listView.isItemChecked(position)) {
|
||||
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.light_youtube_primary_color));
|
||||
} else {
|
||||
convertView.setBackgroundColor(0);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package org.schabi.newpipe;
|
||||
package org.schabi.newpipe.detail;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -11,9 +11,10 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.settings.SettingsActivity;
|
||||
import org.schabi.newpipe.extractor.MediaFormat;
|
||||
import org.schabi.newpipe.extractor.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.VideoStream;
|
||||
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,17 +45,17 @@ class ActionBarHandler {
|
||||
private AppCompatActivity activity;
|
||||
private int selectedVideoStream = -1;
|
||||
|
||||
private SharedPreferences defaultPreferences = null;
|
||||
private SharedPreferences defaultPreferences;
|
||||
|
||||
private Menu menu;
|
||||
|
||||
// Only callbacks are listed here, there are more actions which don't need a callback.
|
||||
// those are edited directly. Typically VideoItemDetailFragment will implement those callbacks.
|
||||
private OnActionListener onShareListener = null;
|
||||
private OnActionListener onOpenInBrowserListener = null;
|
||||
private OnActionListener onDownloadListener = null;
|
||||
private OnActionListener onPlayWithKodiListener = null;
|
||||
private OnActionListener onPlayAudioListener = null;
|
||||
private OnActionListener onShareListener;
|
||||
private OnActionListener onOpenInBrowserListener;
|
||||
private OnActionListener onDownloadListener;
|
||||
private OnActionListener onPlayWithKodiListener;
|
||||
private OnActionListener onPlayAudioListener;
|
||||
|
||||
|
||||
// Triggered when a stream related action is triggered.
|
||||
@@ -110,6 +111,9 @@ class ActionBarHandler {
|
||||
|
||||
|
||||
private int getDefaultResolution(final List<VideoStream> videoStreams) {
|
||||
if (defaultPreferences == null)
|
||||
return 0;
|
||||
|
||||
String defaultResolution = defaultPreferences
|
||||
.getString(activity.getString(R.string.default_resolution_key),
|
||||
activity.getString(R.string.default_resolution_value));
|
||||
@@ -180,6 +184,12 @@ class ActionBarHandler {
|
||||
onPlayAudioListener.onActionSelected(selectedVideoStream);
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_item_downloads: {
|
||||
Intent intent =
|
||||
new Intent(activity, org.schabi.newpipe.download.DownloadActivity.class);
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
Log.e(TAG, "Menu Item not known");
|
||||
}
|
@@ -0,0 +1,220 @@
|
||||
package org.schabi.newpipe.detail;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 02.08.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* StreamInfoWorker.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 StreamInfoWorker {
|
||||
|
||||
private static final String TAG = StreamInfoWorker.class.toString();
|
||||
|
||||
public interface OnStreamInfoReceivedListener {
|
||||
void onReceive(StreamInfo info);
|
||||
void onError(int messageId);
|
||||
void onBlockedByGemaError();
|
||||
void onContentErrorWithMessage(int messageId);
|
||||
void onContentError();
|
||||
}
|
||||
|
||||
private class StreamExtractorRunnable implements Runnable {
|
||||
private final Handler h = new Handler();
|
||||
private StreamExtractor streamExtractor;
|
||||
private final int serviceId;
|
||||
private final String videoUrl;
|
||||
private Activity a;
|
||||
|
||||
public StreamExtractorRunnable(Activity a, String videoUrl, int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
this.videoUrl = videoUrl;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
StreamInfo streamInfo = null;
|
||||
StreamingService service = null;
|
||||
try {
|
||||
service = NewPipe.getService(serviceId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ErrorActivity.reportError(h, a, e, VideoItemDetailFragment.class, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
"", videoUrl, R.string.could_not_get_stream));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
streamExtractor = service.getExtractorInstance(videoUrl);
|
||||
streamInfo = StreamInfo.getVideoInfo(streamExtractor);
|
||||
|
||||
final StreamInfo info = streamInfo;
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener.onReceive(info);
|
||||
}
|
||||
});
|
||||
|
||||
// look for errors during extraction
|
||||
// this if statement only covers extra information.
|
||||
// if these are not available or caused an error, they are just not available
|
||||
// but don't render the stream information unusalbe.
|
||||
if(streamInfo != null &&
|
||||
!streamInfo.errors.isEmpty()) {
|
||||
Log.e(TAG, "OCCURRED ERRORS DURING EXTRACTION:");
|
||||
for (Throwable e : streamInfo.errors) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "------");
|
||||
}
|
||||
|
||||
View rootView = a != null ? a.findViewById(R.id.video_item_detail) : null;
|
||||
ErrorActivity.reportError(h, a,
|
||||
streamInfo.errors, null, rootView,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
service.getServiceInfo().name, videoUrl, 0 /* no message for the user */));
|
||||
}
|
||||
|
||||
// These errors render the stream information unusable.
|
||||
} catch (IOException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener.onError(R.string.network_error);
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
}
|
||||
// custom service related exceptions
|
||||
catch (YoutubeStreamExtractor.DecryptException de) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener.onError(R.string.youtube_signature_decryption_error);
|
||||
}
|
||||
});
|
||||
de.printStackTrace();
|
||||
} catch (YoutubeStreamExtractor.GemaException ge) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener.onBlockedByGemaError();
|
||||
}
|
||||
});
|
||||
} catch(YoutubeStreamExtractor.LiveStreamException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener
|
||||
.onContentErrorWithMessage(R.string.live_streams_not_supported);
|
||||
}
|
||||
});
|
||||
}
|
||||
// ----------------------------------------
|
||||
catch(StreamExtractor.ContentNotAvailableException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onStreamInfoReceivedListener
|
||||
.onContentError();
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
} catch(StreamInfo.StreamExctractException e) {
|
||||
if(!streamInfo.errors.isEmpty()) {
|
||||
// !!! if this case ever kicks in someone gets kicked out !!!
|
||||
ErrorActivity.reportError(h, a, e, VideoItemDetailFragment.class, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
service.getServiceInfo().name, videoUrl, R.string.could_not_get_stream));
|
||||
} else {
|
||||
ErrorActivity.reportError(h, a, streamInfo.errors, VideoItemDetailFragment.class, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
service.getServiceInfo().name, videoUrl, R.string.could_not_get_stream));
|
||||
}
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
a.finish();
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
} catch (ParsingException e) {
|
||||
ErrorActivity.reportError(h, a, e, VideoItemDetailFragment.class, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
service.getServiceInfo().name, videoUrl, R.string.parsing_error));
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
a.finish();
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
} catch(Exception e) {
|
||||
ErrorActivity.reportError(h, a, e, VideoItemDetailFragment.class, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
||||
service.getServiceInfo().name, videoUrl, R.string.general_error));
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
a.finish();
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static StreamInfoWorker streamInfoWorker = null;
|
||||
private StreamExtractorRunnable runnable = null;
|
||||
private OnStreamInfoReceivedListener onStreamInfoReceivedListener = null;
|
||||
|
||||
private StreamInfoWorker() {
|
||||
|
||||
}
|
||||
|
||||
public static StreamInfoWorker getInstance() {
|
||||
return streamInfoWorker == null ? (streamInfoWorker = new StreamInfoWorker()) : streamInfoWorker;
|
||||
}
|
||||
|
||||
public void search(int serviceId, String url, Activity a) {
|
||||
runnable = new StreamExtractorRunnable(a, url, serviceId);
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void setOnStreamInfoReceivedListener(
|
||||
OnStreamInfoReceivedListener onStreamInfoReceivedListener) {
|
||||
this.onStreamInfoReceivedListener = onStreamInfoReceivedListener;
|
||||
}
|
||||
}
|
@@ -0,0 +1,242 @@
|
||||
package org.schabi.newpipe.detail;
|
||||
|
||||
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.App;
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* Removes invisible separators (\p{Z}) and punctuation characters including
|
||||
* brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
|
||||
* more details.
|
||||
*/
|
||||
private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
|
||||
|
||||
private 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
|
||||
//
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
handleIntent(getIntent());
|
||||
} else {
|
||||
videoUrl = savedInstanceState.getString(VideoItemDetailFragment.VIDEO_URL);
|
||||
currentStreamingService = savedInstanceState.getInt(VideoItemDetailFragment.STREAMING_SERVICE);
|
||||
addFragment(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
handleIntent(intent);
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
Bundle arguments = new Bundle();
|
||||
boolean autoplay = false;
|
||||
if (intent.getData() != null) {
|
||||
// this means the video was called though another app
|
||||
videoUrl = intent.getData().toString();
|
||||
currentStreamingService = getServiceIdByUrl(videoUrl);
|
||||
if(currentStreamingService == -1) {
|
||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
autoplay = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean(getString(R.string.autoplay_through_intent_key), false);
|
||||
} else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
||||
//this means that vidoe was called through share menu
|
||||
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
videoUrl = getUris(extraText)[0];
|
||||
currentStreamingService = getServiceIdByUrl(videoUrl);
|
||||
} else {
|
||||
//this is if the video was called through another NewPipe activity
|
||||
videoUrl = intent.getStringExtra(VideoItemDetailFragment.VIDEO_URL);
|
||||
currentStreamingService = intent.getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1);
|
||||
}
|
||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, autoplay);
|
||||
arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
|
||||
addFragment(arguments);
|
||||
}
|
||||
|
||||
private void addFragment(final Bundle arguments) {
|
||||
// Create the detail fragment and add it to the activity
|
||||
// using a fragment transaction.
|
||||
fragment = new VideoItemDetailFragment();
|
||||
fragment.setArguments(arguments);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(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, MainActivity.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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all Strings which look remotely like URLs from a text.
|
||||
* Used if NewPipe was called through share menu.
|
||||
*
|
||||
* @param sharedText text to scan for URLs.
|
||||
* @return potential URLs
|
||||
*/
|
||||
private String[] getUris(final String sharedText) {
|
||||
final Collection<String> result = new HashSet<>();
|
||||
if (sharedText != null) {
|
||||
final String[] array = sharedText.split("\\p{Space}");
|
||||
for (String s : array) {
|
||||
s = trim(s);
|
||||
if (s.length() != 0) {
|
||||
if (s.matches(".+://.+")) {
|
||||
result.add(removeHeadingGibberish(s));
|
||||
} else if (s.matches(".+\\..+")) {
|
||||
result.add("http://" + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
private static String removeHeadingGibberish(final String input) {
|
||||
int start = 0;
|
||||
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
||||
if (!input.substring(i, i + 1).matches("\\p{L}")) {
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return input.substring(start, input.length());
|
||||
}
|
||||
|
||||
private static String trim(final String input) {
|
||||
if (input == null || input.length() < 1) {
|
||||
return input;
|
||||
} else {
|
||||
String output = input;
|
||||
while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
|
||||
output = output.substring(1);
|
||||
}
|
||||
while (output.length() > 0
|
||||
&& output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
|
||||
output = output.substring(0, output.length() - 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
private int getServiceIdByUrl(String url) {
|
||||
StreamingService[] serviceList = NewPipe.getServices();
|
||||
int service = -1;
|
||||
for (int i = 0; i < serviceList.length; i++) {
|
||||
if (serviceList[i].getUrlIdHandlerInstance().acceptUrl(videoUrl)) {
|
||||
service = i;
|
||||
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return service;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user