mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-09-30 16:20:54 +02:00
Compare commits
198 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2f181ce7c9 | ||
![]() |
3a13d4a1de | ||
![]() |
719de00e0f | ||
![]() |
ddffe99f53 | ||
![]() |
9ade596f06 | ||
![]() |
46f413b7f2 | ||
![]() |
5fe2e7b8ad | ||
![]() |
3008cbb5f4 | ||
![]() |
f7983960e5 | ||
![]() |
bb8007bb7c | ||
![]() |
01751ba97a | ||
![]() |
f41475d11c | ||
![]() |
d8914d9b6d | ||
![]() |
94cc2ad365 | ||
![]() |
e07464b81c | ||
![]() |
9d231b55b5 | ||
![]() |
77d8dac3c1 | ||
![]() |
e160015283 | ||
![]() |
aeb0cac3ee | ||
![]() |
a539f94837 | ||
![]() |
df70751071 | ||
![]() |
e55f1dff78 | ||
![]() |
47646e1c62 | ||
![]() |
80e673f20c | ||
![]() |
9ca8c5480c | ||
![]() |
4d0d3c7ead | ||
![]() |
58137aadc9 | ||
![]() |
82a59ae479 | ||
![]() |
affd23b14e | ||
![]() |
9c7f249756 | ||
![]() |
e2a0502171 | ||
![]() |
3832a4b355 | ||
![]() |
84f059415c | ||
![]() |
bb292e3199 | ||
![]() |
70541bf561 | ||
![]() |
48dd8e88e3 | ||
![]() |
52c2e0899d | ||
![]() |
9955d5b62f | ||
![]() |
8e26247fa1 | ||
![]() |
72924e2692 | ||
![]() |
8c2c8d630f | ||
![]() |
5ccf0baa6b | ||
![]() |
8fff0ccdf2 | ||
![]() |
35264bfb97 | ||
![]() |
4c9b0dc8e9 | ||
![]() |
4deb7caa83 | ||
![]() |
45f1a512b4 | ||
![]() |
ab95fdc087 | ||
![]() |
df608b9ded | ||
![]() |
6a4c81d160 | ||
![]() |
040d658540 | ||
![]() |
cbc9913e9c | ||
![]() |
f007cbd5ee | ||
![]() |
7351591df7 | ||
![]() |
5222d4cbba | ||
![]() |
ef9966815e | ||
![]() |
ad73440ce9 | ||
![]() |
c81cfdc455 | ||
![]() |
134c3804db | ||
![]() |
e355df5eda | ||
![]() |
a68e0a95f4 | ||
![]() |
6fd6facf72 | ||
![]() |
00102d4048 | ||
![]() |
adbeff11d4 | ||
![]() |
a8fe329678 | ||
![]() |
a4b61bf730 | ||
![]() |
ee592def0c | ||
![]() |
c14e117239 | ||
![]() |
b6e94dde0c | ||
![]() |
63a4a44d7e | ||
![]() |
eb8ab5d527 | ||
![]() |
b778d40d65 | ||
![]() |
2f570672dc | ||
![]() |
9290ed490f | ||
![]() |
1bda812c75 | ||
![]() |
ab82406c98 | ||
![]() |
be763349df | ||
![]() |
91764ad601 | ||
![]() |
1c4031aa38 | ||
![]() |
c3bc648dd4 | ||
![]() |
c97d794272 | ||
![]() |
8e7d2e91e9 | ||
![]() |
cf0fbbbd3d | ||
![]() |
7d3ede7946 | ||
![]() |
1aa308eb5d | ||
![]() |
4bfd30e34a | ||
![]() |
0f46c90688 | ||
![]() |
aa2173fc4a | ||
![]() |
932cb1d19c | ||
![]() |
18b038d8e4 | ||
![]() |
2ac71c75c0 | ||
![]() |
4067ba5232 | ||
![]() |
ab47dd5a5b | ||
![]() |
3130910307 | ||
![]() |
22113439a4 | ||
![]() |
2d25a9ad7a | ||
![]() |
8f0a2cc2f0 | ||
![]() |
4ca39258c9 | ||
![]() |
d0c0238b8b | ||
![]() |
f9f08e5169 | ||
![]() |
cfc51b2401 | ||
![]() |
54c2704cb5 | ||
![]() |
9b51c946fe | ||
![]() |
06f38cbcb4 | ||
![]() |
f368d6b257 | ||
![]() |
f4301da14d | ||
![]() |
f34c09f165 | ||
![]() |
6d1db56512 | ||
![]() |
b70c07d004 | ||
![]() |
f9f48a5eb6 | ||
![]() |
14e4e73444 | ||
![]() |
f2ce4d2daf | ||
![]() |
468ebdda87 | ||
![]() |
a1f0fb3b14 | ||
![]() |
3c9f4de234 | ||
![]() |
8ae411619f | ||
![]() |
61e5c9121a | ||
![]() |
8a3cf0d5dc | ||
![]() |
ecb5df65ac | ||
![]() |
5f1e98a0d3 | ||
![]() |
3b9a477499 | ||
![]() |
e5bf98a741 | ||
![]() |
06fafc247e | ||
![]() |
e8bb17b631 | ||
![]() |
363cd07883 | ||
![]() |
2b4a9286c4 | ||
![]() |
34c985026f | ||
![]() |
4a0aa42914 | ||
![]() |
746c2a15bf | ||
![]() |
9318bb5306 | ||
![]() |
2a10ceb74f | ||
![]() |
83f4db59e2 | ||
![]() |
9f66f759ad | ||
![]() |
6f015349e8 | ||
![]() |
a37802c2b9 | ||
![]() |
4fa3baf5e1 | ||
![]() |
ef8c2c81d5 | ||
![]() |
8c80d8c457 | ||
![]() |
1596872c54 | ||
![]() |
da8873fa78 | ||
![]() |
ecd8439b3f | ||
![]() |
5d178532ac | ||
![]() |
08e40a013d | ||
![]() |
c136f7363c | ||
![]() |
a60f10d739 | ||
![]() |
ae46afcb42 | ||
![]() |
bffb9f6800 | ||
![]() |
79aa9ad04b | ||
![]() |
ff5714f04a | ||
![]() |
ce499a9766 | ||
![]() |
d3bb8b7651 | ||
![]() |
6d9c23c4cb | ||
![]() |
b95a9332a9 | ||
![]() |
609715eb5c | ||
![]() |
a1266c919c | ||
![]() |
a1925a0302 | ||
![]() |
a7a4c03372 | ||
![]() |
37201600e0 | ||
![]() |
a94f40ed62 | ||
![]() |
0b08cf8c76 | ||
![]() |
33e29be7db | ||
![]() |
bd1c7851c7 | ||
![]() |
82faea5965 | ||
![]() |
0bbbfd3217 | ||
![]() |
fb578ecda8 | ||
![]() |
e804647a65 | ||
![]() |
c3c3a94593 | ||
![]() |
9d55569f80 | ||
![]() |
5dd8271c15 | ||
![]() |
7a4a54c3ea | ||
![]() |
7c9078a625 | ||
![]() |
71ae342f52 | ||
![]() |
b43c56085d | ||
![]() |
83d2ab95e0 | ||
![]() |
20a8d7372c | ||
![]() |
c36ba88db7 | ||
![]() |
4aa23023ee | ||
![]() |
8735cf931a | ||
![]() |
2473069326 | ||
![]() |
03bab57a97 | ||
![]() |
e3baf69533 | ||
![]() |
461f747af1 | ||
![]() |
028872a7d8 | ||
![]() |
a1483b6c55 | ||
![]() |
e406ba094c | ||
![]() |
c100d15ba8 | ||
![]() |
b4ea592638 | ||
![]() |
16b757d9a3 | ||
![]() |
2aa801a392 | ||
![]() |
b838344526 | ||
![]() |
233a3df222 | ||
![]() |
da6661b1ea | ||
![]() |
c6e120fc51 | ||
![]() |
c416a1254d | ||
![]() |
2aa4f6ddda | ||
![]() |
129597023d | ||
![]() |
02aed86b7e | ||
![]() |
e44f4b5823 |
24
.travis.yml
24
.travis.yml
@@ -5,35 +5,15 @@ android:
|
|||||||
components:
|
components:
|
||||||
# The BuildTools version used by NewPipe
|
# The BuildTools version used by NewPipe
|
||||||
- tools
|
- tools
|
||||||
- build-tools-25.0.0
|
- build-tools-25.0.2
|
||||||
|
|
||||||
# The SDK version used to compile NewPipe
|
# The SDK version used to compile NewPipe
|
||||||
- android-25
|
- android-25
|
||||||
|
|
||||||
# Additional components
|
# Additional components
|
||||||
- extra-android-support
|
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
- extra-google-m2repository
|
|
||||||
|
|
||||||
# Emulators
|
script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest
|
||||||
- sys-img-armeabi-v7a-android-21
|
|
||||||
- sys-img-armeabi-v7a-android-19
|
|
||||||
- sys-img-armeabi-v7a-android-15
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- ADB_INSTALL_TIMEOUT=8 # minutes (2 by default)
|
|
||||||
- GRADLE_OPTS=-Xmx512m # give gradle more memory since it seem to fail otherwise
|
|
||||||
matrix:
|
|
||||||
- ANDROID_TARGET=android-21 ANDROID_ABI=armeabi-v7a
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
|
|
||||||
- emulator -avd test -no-skin -no-audio -no-window &
|
|
||||||
- android-wait-for-emulator
|
|
||||||
- adb shell input keyevent 82 &
|
|
||||||
|
|
||||||
script: ./gradlew --info build connectedCheck
|
|
||||||
|
|
||||||
licenses:
|
licenses:
|
||||||
- '.+'
|
- '.+'
|
||||||
|
26
README.md
26
README.md
@@ -19,11 +19,16 @@ Project status:
|
|||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
[<img src="screenshots/screenshot_1.png" width=150>](screenshots/screenshot_1.png)
|
[<img src="screenshots/screenshot_1.png" width=160>](screenshots/screenshot_1.png)
|
||||||
[<img src="screenshots/screenshot_2.png" width=150>](screenshots/screenshot_2.png)
|
[<img src="screenshots/screenshot_2.png" width=160>](screenshots/screenshot_2.png)
|
||||||
[<img src="screenshots/screenshot_3.png" width=150>](screenshots/screenshot_3.png)
|
[<img src="screenshots/screenshot_3.png" width=160>](screenshots/screenshot_3.png)
|
||||||
[<img src="screenshots/screenshot_4.png" width=150>](screenshots/screenshot_4.png)
|
[<img src="screenshots/screenshot_4.png" width=160>](screenshots/screenshot_4.png)
|
||||||
[<img src="screenshots/screenshot_5.png" width=150>](screenshots/screenshot_5.png)
|
[<img src="screenshots/screenshot_5.png" width=160>](screenshots/screenshot_5.png)
|
||||||
|
[<img src="screenshots/screenshot_6.png" width=160>](screenshots/screenshot_6.png)
|
||||||
|
[<img src="screenshots/screenshot_7.png" width=160>](screenshots/screenshot_7.png)
|
||||||
|
[<img src="screenshots/screenshot_8.png" width=160>](screenshots/screenshot_8.png)
|
||||||
|
[<img src="screenshots/screenshot_9.png" width=160>](screenshots/screenshot_9.png)
|
||||||
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@@ -35,25 +40,30 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Display general information about a video
|
* Display general information about a video
|
||||||
* Watch YouTube videos
|
* Watch YouTube videos
|
||||||
* Listen to YouTube videos (experimental)
|
* Listen to YouTube videos (experimental)
|
||||||
|
* Popup mode (floating player)
|
||||||
* Select the streaming player to watch the video with
|
* Select the streaming player to watch the video with
|
||||||
* Download videos
|
* Download videos
|
||||||
* Download audio only * Open a video in Kodi
|
* Download audio only
|
||||||
|
* Open a video in Kodi
|
||||||
* Show Next/Related videos
|
* Show Next/Related videos
|
||||||
* Search YouTube in a specific language
|
* Search YouTube in a specific language
|
||||||
* Watch age restricted material
|
* Watch age restricted material
|
||||||
* Display general information about channels
|
* Display general information about channels
|
||||||
* Search channels
|
* Search channels
|
||||||
|
* Watch videos from a channel
|
||||||
|
* Orbot/Tor support (not yet directly)
|
||||||
|
* 1080p/2k/4k support
|
||||||
|
|
||||||
### Coming Features
|
### Coming Features
|
||||||
|
|
||||||
* Orbot/Tor support
|
|
||||||
* Bookmarks
|
* Bookmarks
|
||||||
* View history
|
* View history
|
||||||
* Search history
|
* Search history
|
||||||
* Subscribe to channels
|
* Subscribe to channels
|
||||||
* Watch videos from a channel
|
|
||||||
* Search/Watch Playlists
|
* Search/Watch Playlists
|
||||||
* Queeing videos
|
* Queeing videos
|
||||||
|
* Subtitles support
|
||||||
|
* livestream support
|
||||||
* ... and many more
|
* ... and many more
|
||||||
|
|
||||||
### Multiservice support
|
### Multiservice support
|
||||||
|
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 25
|
||||||
buildToolsVersion '25.0.0'
|
buildToolsVersion '25.0.2'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 26
|
versionCode 33
|
||||||
versionName "0.8.12"
|
versionName "0.9.6"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -31,22 +31,24 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.12'
|
|
||||||
compile 'com.android.support:appcompat-v7:25.1.0'
|
|
||||||
compile 'com.android.support:support-v4:25.1.0'
|
|
||||||
compile 'com.android.support:design:25.1.0'
|
|
||||||
compile 'com.android.support:recyclerview-v7:25.1.0'
|
|
||||||
compile 'org.jsoup:jsoup:1.8.3'
|
|
||||||
compile 'org.mozilla:rhino:1.7.7'
|
|
||||||
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
|
||||||
compile 'de.hdodenhof:circleimageview:2.0.0'
|
|
||||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
|
||||||
compile 'com.github.nirhart:parallaxscroll:1.0'
|
|
||||||
compile 'com.google.code.gson:gson:2.4'
|
|
||||||
compile 'com.nononsenseapps:filepicker:3.0.0'
|
|
||||||
compile 'ch.acra:acra:4.9.0'
|
|
||||||
compile 'com.devbrackets.android:exomedia:3.1.1'
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||||
testCompile 'org.json:json:20160810'
|
testCompile 'org.json:json:20160810'
|
||||||
|
|
||||||
|
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||||
|
compile 'com.android.support:support-v4:25.3.1'
|
||||||
|
compile 'com.android.support:design:25.3.1'
|
||||||
|
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||||
|
|
||||||
|
compile 'com.google.code.gson:gson:2.7'
|
||||||
|
compile 'org.jsoup:jsoup:1.8.3'
|
||||||
|
compile 'org.mozilla:rhino:1.7.7'
|
||||||
|
compile 'ch.acra:acra:4.9.0'
|
||||||
|
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
||||||
|
|
||||||
|
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||||
|
compile 'de.hdodenhof:circleimageview:2.0.0'
|
||||||
|
compile 'com.github.nirhart:parallaxscroll:1.0'
|
||||||
|
compile 'com.nononsenseapps:filepicker:3.0.0'
|
||||||
|
compile 'com.google.android.exoplayer:exoplayer:r2.3.1'
|
||||||
}
|
}
|
||||||
|
@@ -19,22 +19,15 @@
|
|||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name"
|
||||||
|
android:launchMode="singleTask">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
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=".MainActivity" />
|
|
||||||
</activity>
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".player.PlayVideoActivity"
|
android:name=".player.PlayVideoActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
@@ -47,28 +40,11 @@
|
|||||||
android:label="@string/background_player_name" />
|
android:label="@string/background_player_name" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".player.ExoPlayerActivity"
|
android:name=".player.MainVideoPlayer"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/PlayerTheme">
|
android:theme="@style/PlayerTheme"/>
|
||||||
<intent-filter>
|
|
||||||
<action android:name="org.schabi.newpipe.exoplayer.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
|
|
||||||
<data android:scheme="http" />
|
|
||||||
<data android:scheme="https" />
|
|
||||||
<data android:scheme="content" />
|
|
||||||
<data android:scheme="asset" />
|
|
||||||
<data android:scheme="file" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".player.BackgroundPlayer"
|
|
||||||
android:exported="false"
|
|
||||||
android:label="@string/background_player_name" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".settings.SettingsActivity"
|
android:name=".settings.SettingsActivity"
|
||||||
@@ -104,9 +80,6 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/FilePickerTheme"/>
|
android:theme="@style/FilePickerTheme"/>
|
||||||
<activity
|
|
||||||
android:name=".ChannelActivity"
|
|
||||||
android:launchMode="singleTask" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ReCaptchaActivity"
|
android:name=".ReCaptchaActivity"
|
||||||
android:label="@string/reCaptchaActivity" />
|
android:label="@string/reCaptchaActivity" />
|
||||||
@@ -121,7 +94,9 @@
|
|||||||
android:resource="@xml/provider_paths" />
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<activity android:name=".RouterActivity"
|
<activity
|
||||||
|
android:name=".RouterActivity"
|
||||||
|
android:taskAffinity=""
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -138,6 +113,7 @@
|
|||||||
<data android:host="www.youtube.com" />
|
<data android:host="www.youtube.com" />
|
||||||
<!-- video prefix -->
|
<!-- video prefix -->
|
||||||
<data android:pathPrefix="/v/" />
|
<data android:pathPrefix="/v/" />
|
||||||
|
<data android:pathPrefix="/embed/" />
|
||||||
<data android:pathPrefix="/watch" />
|
<data android:pathPrefix="/watch" />
|
||||||
<data android:pathPrefix="/attribution_link" />
|
<data android:pathPrefix="/attribution_link" />
|
||||||
<!-- channel prefix -->
|
<!-- channel prefix -->
|
||||||
@@ -177,9 +153,11 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".PopupActivity"
|
<activity
|
||||||
|
android:name=".RouterPopupActivity"
|
||||||
|
android:taskAffinity=""
|
||||||
android:theme="@android:style/Theme.NoDisplay"
|
android:theme="@android:style/Theme.NoDisplay"
|
||||||
android:label="NewPipe Popup mode">
|
android:label="@string/popup_mode_share_menu_title">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
||||||
@@ -195,11 +173,9 @@
|
|||||||
<data android:host="www.youtube.com" />
|
<data android:host="www.youtube.com" />
|
||||||
<!-- video prefix -->
|
<!-- video prefix -->
|
||||||
<data android:pathPrefix="/v/" />
|
<data android:pathPrefix="/v/" />
|
||||||
|
<data android:pathPrefix="/embed/" />
|
||||||
<data android:pathPrefix="/watch" />
|
<data android:pathPrefix="/watch" />
|
||||||
<data android:pathPrefix="/attribution_link" />
|
<data android:pathPrefix="/attribution_link" />
|
||||||
<!-- channel prefix -->
|
|
||||||
<data android:pathPrefix="/channel/"/>
|
|
||||||
<data android:pathPrefix="/user/"/>
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -227,9 +203,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
@@ -238,4 +212,4 @@
|
|||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@@ -20,10 +20,6 @@ package org.schabi.newpipe;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton:
|
* Singleton:
|
||||||
* Used to send data between certain Activity/Services within the same process.
|
* Used to send data between certain Activity/Services within the same process.
|
||||||
@@ -39,8 +35,5 @@ public class ActivityCommunicator {
|
|||||||
return activityCommunicator;
|
return activityCommunicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thumbnail send from VideoItemDetailFragment to BackgroundPlayer
|
|
||||||
public volatile Bitmap backgroundPlayerThumbnail;
|
|
||||||
|
|
||||||
public volatile Class returnActivity;
|
public volatile Class returnActivity;
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||||||
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import info.guardianproject.netcipher.NetCipher;
|
import info.guardianproject.netcipher.NetCipher;
|
||||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||||
@@ -82,6 +83,8 @@ public class App extends Application {
|
|||||||
// DO NOT REMOVE THIS FUNCTION!!!
|
// DO NOT REMOVE THIS FUNCTION!!!
|
||||||
// Otherwise downloadPathPreference has invalid value.
|
// Otherwise downloadPathPreference has invalid value.
|
||||||
SettingsActivity.initSettings(this);
|
SettingsActivity.initSettings(this);
|
||||||
|
|
||||||
|
ThemeHelper.setTheme(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||||
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 01.08.16.
|
* Created by Christian Schabesberger on 01.08.16.
|
||||||
@@ -33,11 +33,11 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||||||
public class ImageErrorLoadingListener implements ImageLoadingListener {
|
public class ImageErrorLoadingListener implements ImageLoadingListener {
|
||||||
|
|
||||||
private int serviceId = -1;
|
private int serviceId = -1;
|
||||||
private Activity activity = null;
|
private Context context = null;
|
||||||
private View rootView = null;
|
private View rootView = null;
|
||||||
|
|
||||||
public ImageErrorLoadingListener(Activity activity, View rootView, int serviceId) {
|
public ImageErrorLoadingListener(Context context, View rootView, int serviceId) {
|
||||||
this.activity = activity;
|
this.context = context;
|
||||||
this.serviceId= serviceId;
|
this.serviceId= serviceId;
|
||||||
this.rootView = rootView;
|
this.rootView = rootView;
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ public class ImageErrorLoadingListener implements ImageLoadingListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||||
ErrorActivity.reportError(activity,
|
ErrorActivity.reportError(context,
|
||||||
failReason.getCause(), null, rootView,
|
failReason.getCause(), null, rootView,
|
||||||
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
|
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
|
||||||
NewPipe.getNameOfService(serviceId), imageUri,
|
NewPipe.getNameOfService(serviceId), imageUri,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ import android.os.Bundle;
|
|||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.webkit.CookieManager;
|
import android.webkit.CookieManager;
|
||||||
import android.webkit.ValueCallback;
|
import android.webkit.ValueCallback;
|
||||||
@@ -48,10 +49,15 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
// Set return to Cancel by default
|
// Set return to Cancel by default
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
|
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
if (actionBar != null) {
|
||||||
actionBar.setTitle(R.string.reCaptcha_title);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setDisplayShowTitleEnabled(true);
|
actionBar.setTitle(R.string.reCaptcha_title);
|
||||||
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
WebView myWebView = (WebView) findViewById(R.id.reCaptchaWebView);
|
WebView myWebView = (WebView) findViewById(R.id.reCaptchaWebView);
|
||||||
|
|
||||||
|
@@ -2,22 +2,15 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.detail.VideoItemDetailActivity;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.detail.VideoItemDetailFragment;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.util.NavStack;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
||||||
* RouterActivity .java is part of NewPipe.
|
* RouterActivity .java is part of NewPipe.
|
||||||
*
|
*
|
||||||
@@ -40,7 +33,7 @@ import java.util.HashSet;
|
|||||||
* to the part of the service which can handle the url.
|
* to the part of the service which can handle the url.
|
||||||
*/
|
*/
|
||||||
public class RouterActivity extends Activity {
|
public class RouterActivity extends Activity {
|
||||||
private static final String TAG = RouterActivity.class.toString();
|
//private static final String TAG = "RouterActivity"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes invisible separators (\p{Z}) and punctuation characters including
|
* Removes invisible separators (\p{Z}) and punctuation characters including
|
||||||
@@ -56,6 +49,25 @@ public class RouterActivity extends Activity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleIntent(Intent intent) {
|
||||||
|
String videoUrl = "";
|
||||||
|
|
||||||
|
// first gather data and find service
|
||||||
|
if (intent.getData() != null) {
|
||||||
|
// this means the video was called though another app
|
||||||
|
videoUrl = intent.getData().toString();
|
||||||
|
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
||||||
|
//this means that vidoe was called through share menu
|
||||||
|
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
videoUrl = getUris(extraText)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
NavigationHelper.openByLink(this, videoUrl);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String removeHeadingGibberish(final String input) {
|
private static String removeHeadingGibberish(final String input) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
@@ -109,50 +121,4 @@ public class RouterActivity extends Activity {
|
|||||||
return result.toArray(new String[result.size()]);
|
return result.toArray(new String[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntent(Intent intent) {
|
|
||||||
String videoUrl = "";
|
|
||||||
StreamingService service = null;
|
|
||||||
|
|
||||||
// first gather data and find service
|
|
||||||
if (intent.getData() != null) {
|
|
||||||
// this means the video was called though another app
|
|
||||||
videoUrl = intent.getData().toString();
|
|
||||||
} else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
|
||||||
//this means that vidoe was called through share menu
|
|
||||||
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
||||||
videoUrl = getUris(extraText)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
service = NewPipe.getServiceByUrl(videoUrl);
|
|
||||||
if(service == null) {
|
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Intent callIntent = new Intent();
|
|
||||||
switch(service.getLinkTypeByUrl(videoUrl)) {
|
|
||||||
case CHANNEL:
|
|
||||||
callIntent.setClass(this, ChannelActivity.class);
|
|
||||||
break;
|
|
||||||
case STREAM:
|
|
||||||
callIntent.setClass(this, VideoItemDetailActivity.class);
|
|
||||||
callIntent.putExtra(VideoItemDetailFragment.AUTO_PLAY,
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getBoolean(
|
|
||||||
getString(R.string.autoplay_through_intent_key), false));
|
|
||||||
break;
|
|
||||||
case PLAYLIST:
|
|
||||||
Log.e(TAG, "NOT YET DEFINED");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callIntent.putExtra(NavStack.URL, videoUrl);
|
|
||||||
callIntent.putExtra(NavStack.SERVICE_ID, service.getServiceId());
|
|
||||||
startActivity(callIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -4,24 +4,22 @@ import android.app.Activity;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
import org.schabi.newpipe.player.PopupVideoPlayer;
|
||||||
import org.schabi.newpipe.util.NavStack;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This activity is thought to open video streams form an external app using the popup playser.
|
* This activity is thought to open video streams form an external app using the popup player.
|
||||||
*/
|
*/
|
||||||
|
public class RouterPopupActivity extends Activity {
|
||||||
public class PopupActivity extends Activity {
|
//private static final String TAG = "RouterPopupActivity";
|
||||||
private static final String TAG = RouterActivity.class.toString();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes invisible separators (\p{Z}) and punctuation characters including
|
* Removes invisible separators (\p{Z}) and punctuation characters including
|
||||||
@@ -38,6 +36,45 @@ public class PopupActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void handleIntent(Intent intent) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
&& !PermissionHelper.checkSystemAlertWindowPermission(this)) {
|
||||||
|
Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String videoUrl = "";
|
||||||
|
StreamingService service;
|
||||||
|
|
||||||
|
// first gather data and find service
|
||||||
|
if (intent.getData() != null) {
|
||||||
|
// this means the video was called though another app
|
||||||
|
videoUrl = intent.getData().toString();
|
||||||
|
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
||||||
|
//this means that vidoe was called through share menu
|
||||||
|
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
videoUrl = getUris(extraText)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
service = NewPipe.getServiceByUrl(videoUrl);
|
||||||
|
if (service == null) {
|
||||||
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent callIntent = new Intent(this, PopupVideoPlayer.class);
|
||||||
|
switch (service.getLinkTypeByUrl(videoUrl)) {
|
||||||
|
case STREAM:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callIntent.putExtra(Constants.KEY_URL, videoUrl);
|
||||||
|
callIntent.putExtra(Constants.KEY_SERVICE_ID, service.getServiceId());
|
||||||
|
startService(callIntent);
|
||||||
|
}
|
||||||
|
|
||||||
private static String removeHeadingGibberish(final String input) {
|
private static String removeHeadingGibberish(final String input) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
||||||
@@ -90,47 +127,4 @@ public class PopupActivity extends Activity {
|
|||||||
return result.toArray(new String[result.size()]);
|
return result.toArray(new String[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntent(Intent intent) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
|
||||||
&& !PermissionHelper.checkSystemAlertWindowPermission(this)) {
|
|
||||||
Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String videoUrl = "";
|
|
||||||
StreamingService service = null;
|
|
||||||
|
|
||||||
// first gather data and find service
|
|
||||||
if (intent.getData() != null) {
|
|
||||||
// this means the video was called though another app
|
|
||||||
videoUrl = intent.getData().toString();
|
|
||||||
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
|
||||||
//this means that vidoe was called through share menu
|
|
||||||
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
||||||
videoUrl = getUris(extraText)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
service = NewPipe.getServiceByUrl(videoUrl);
|
|
||||||
if (service == null) {
|
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Intent callIntent = new Intent();
|
|
||||||
switch (service.getLinkTypeByUrl(videoUrl)) {
|
|
||||||
case STREAM:
|
|
||||||
callIntent.setClass(this, PopupVideoPlayer.class);
|
|
||||||
break;
|
|
||||||
case PLAYLIST:
|
|
||||||
Log.e(TAG, "NOT YET DEFINED");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callIntent.putExtra(NavStack.URL, videoUrl);
|
|
||||||
callIntent.putExtra(NavStack.SERVICE_ID, service.getServiceId());
|
|
||||||
startService(callIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,28 +0,0 @@
|
|||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
public class ThemableActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,245 +0,0 @@
|
|||||||
package org.schabi.newpipe.detail;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v7.app.ActionBar;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
|
||||||
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Christian Schabesberger on 18.08.15.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
|
||||||
* DetailsMenuHandler.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
class ActionBarHandler {
|
|
||||||
private static final String TAG = ActionBarHandler.class.toString();
|
|
||||||
|
|
||||||
private AppCompatActivity activity;
|
|
||||||
private int selectedVideoStream = -1;
|
|
||||||
|
|
||||||
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;
|
|
||||||
private OnActionListener onOpenInBrowserListener;
|
|
||||||
private OnActionListener onOpenInPopupListener;
|
|
||||||
private OnActionListener onDownloadListener;
|
|
||||||
private OnActionListener onPlayWithKodiListener;
|
|
||||||
private OnActionListener onPlayAudioListener;
|
|
||||||
|
|
||||||
|
|
||||||
// Triggered when a stream related action is triggered.
|
|
||||||
public interface OnActionListener {
|
|
||||||
void onActionSelected(int selectedStreamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarHandler(AppCompatActivity activity) {
|
|
||||||
this.activity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"deprecation", "ConstantConditions"})
|
|
||||||
public void setupNavMenu(AppCompatActivity activity) {
|
|
||||||
this.activity = activity;
|
|
||||||
try {
|
|
||||||
activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setupStreamList(final List<VideoStream> videoStreams) {
|
|
||||||
if (activity != null) {
|
|
||||||
selectedVideoStream = 0;
|
|
||||||
|
|
||||||
|
|
||||||
// this array will be shown in the dropdown menu for selecting the stream/resolution.
|
|
||||||
String[] itemArray = new String[videoStreams.size()];
|
|
||||||
for (int i = 0; i < videoStreams.size(); i++) {
|
|
||||||
VideoStream item = videoStreams.get(i);
|
|
||||||
itemArray[i] = MediaFormat.getNameById(item.format) + " " + item.resolution;
|
|
||||||
}
|
|
||||||
int defaultResolution = getDefaultResolution(videoStreams);
|
|
||||||
|
|
||||||
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(activity.getBaseContext(),
|
|
||||||
android.R.layout.simple_spinner_dropdown_item, itemArray);
|
|
||||||
|
|
||||||
ActionBar ab = activity.getSupportActionBar();
|
|
||||||
//todo: make this throwsable
|
|
||||||
assert ab != null : "Could not get actionbar";
|
|
||||||
ab.setListNavigationCallbacks(itemAdapter
|
|
||||||
, new ActionBar.OnNavigationListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
|
||||||
selectedVideoStream = (int) itemId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ab.setSelectedNavigationItem(defaultResolution);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
for (int i = 0; i < videoStreams.size(); i++) {
|
|
||||||
VideoStream item = videoStreams.get(i);
|
|
||||||
if (defaultResolution.equals(item.resolution)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// this is actually an error,
|
|
||||||
// but maybe there is really no stream fitting to the default value.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setupMenu(Menu menu, MenuInflater inflater) {
|
|
||||||
this.menu = menu;
|
|
||||||
|
|
||||||
// CAUTION set item properties programmatically otherwise it would not be accepted by
|
|
||||||
// appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
|
|
||||||
|
|
||||||
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
|
||||||
inflater.inflate(R.menu.videoitem_detail, menu);
|
|
||||||
|
|
||||||
showPlayWithKodiAction(defaultPreferences
|
|
||||||
.getBoolean(activity.getString(R.string.show_play_with_kodi_key), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onItemSelected(MenuItem item) {
|
|
||||||
int id = item.getItemId();
|
|
||||||
switch (id) {
|
|
||||||
case R.id.menu_item_share: {
|
|
||||||
/*
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Intent.ACTION_SEND);
|
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, websiteUrl);
|
|
||||||
intent.setType("text/plain");
|
|
||||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title)));
|
|
||||||
*/
|
|
||||||
if(onShareListener != null) {
|
|
||||||
onShareListener.onActionSelected(selectedVideoStream);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case R.id.menu_item_openInBrowser: {
|
|
||||||
if(onOpenInBrowserListener != null) {
|
|
||||||
onOpenInBrowserListener.onActionSelected(selectedVideoStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case R.id.menu_item_download:
|
|
||||||
if(onDownloadListener != null) {
|
|
||||||
onDownloadListener.onActionSelected(selectedVideoStream);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case R.id.action_settings: {
|
|
||||||
Intent intent = new Intent(activity, SettingsActivity.class);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case R.id.action_play_with_kodi:
|
|
||||||
if(onPlayWithKodiListener != null) {
|
|
||||||
onPlayWithKodiListener.onActionSelected(selectedVideoStream);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case R.id.menu_item_play_audio:
|
|
||||||
if(onPlayAudioListener != null) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case R.id.menu_item_popup: {
|
|
||||||
if(onOpenInPopupListener != null) {
|
|
||||||
onOpenInPopupListener.onActionSelected(selectedVideoStream);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Log.e(TAG, "Menu Item not known");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSelectedVideoStream() {
|
|
||||||
return selectedVideoStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnShareListener(OnActionListener listener) {
|
|
||||||
onShareListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnOpenInBrowserListener(OnActionListener listener) {
|
|
||||||
onOpenInBrowserListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnOpenInPopupListener(OnActionListener listener) {
|
|
||||||
onOpenInPopupListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnDownloadListener(OnActionListener listener) {
|
|
||||||
onDownloadListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnPlayWithKodiListener(OnActionListener listener) {
|
|
||||||
onPlayWithKodiListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnPlayAudioListener(OnActionListener listener) {
|
|
||||||
onPlayAudioListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showAudioAction(boolean visible) {
|
|
||||||
menu.findItem(R.id.menu_item_play_audio).setVisible(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showDownloadAction(boolean visible) {
|
|
||||||
menu.findItem(R.id.menu_item_download).setVisible(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showPlayWithKodiAction(boolean visible) {
|
|
||||||
menu.findItem(R.id.action_play_with_kodi).setVisible(visible);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,230 +0,0 @@
|
|||||||
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.extractor.exceptions.ParsingException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
||||||
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 onReCaptchaException();
|
|
||||||
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 (ReCaptchaException e) {
|
|
||||||
h.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onStreamInfoReceivedListener.onReCaptchaException();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
h.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onStreamInfoReceivedListener.onError(R.string.network_error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (YoutubeStreamExtractor.DecryptException de) {
|
|
||||||
// custom service related exceptions
|
|
||||||
ErrorActivity.reportError(h, a, de, VideoItemDetailFragment.class, null,
|
|
||||||
ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM,
|
|
||||||
service.getServiceInfo().name, videoUrl, R.string.youtube_signature_decryption_error));
|
|
||||||
h.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
a.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,155 +0,0 @@
|
|||||||
package org.schabi.newpipe.detail;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.App;
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.util.NavStack;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
ThemeHelper.setTheme(this, true);
|
|
||||||
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(NavStack.URL);
|
|
||||||
currentStreamingService = savedInstanceState.getInt(NavStack.SERVICE_ID);
|
|
||||||
NavStack.getInstance()
|
|
||||||
.restoreSavedInstanceState(savedInstanceState);
|
|
||||||
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;
|
|
||||||
|
|
||||||
videoUrl = intent.getStringExtra(NavStack.URL);
|
|
||||||
currentStreamingService = intent.getIntExtra(NavStack.SERVICE_ID, -1);
|
|
||||||
if(intent.hasExtra(VideoItemDetailFragment.AUTO_PLAY)) {
|
|
||||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
|
||||||
intent.getBooleanExtra(VideoItemDetailFragment.AUTO_PLAY, false));
|
|
||||||
}
|
|
||||||
arguments.putString(NavStack.URL, videoUrl);
|
|
||||||
arguments.putInt(NavStack.SERVICE_ID, 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) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
outState.putString(NavStack.URL, videoUrl);
|
|
||||||
outState.putInt(NavStack.SERVICE_ID, currentStreamingService);
|
|
||||||
outState.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
|
|
||||||
NavStack.getInstance()
|
|
||||||
.onSaveInstanceState(outState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
super.onOptionsItemSelected(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
|
|
||||||
|
|
||||||
NavStack.getInstance()
|
|
||||||
.openMainActivity(this);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
try {
|
|
||||||
NavStack.getInstance()
|
|
||||||
.navBack(this);
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportUiError(this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NavUtils;
|
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
@@ -26,13 +25,11 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.ui.fragment.AllMissionsFragment;
|
import us.shandian.giga.ui.fragment.AllMissionsFragment;
|
||||||
@@ -64,17 +61,19 @@ public class DownloadActivity extends AppCompatActivity implements AdapterView.O
|
|||||||
i.setClass(this, DownloadManagerService.class);
|
i.setClass(this, DownloadManagerService.class);
|
||||||
startService(i);
|
startService(i);
|
||||||
|
|
||||||
|
ThemeHelper.setTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
ThemeHelper.setTheme(this, true);
|
|
||||||
setContentView(R.layout.activity_downloader);
|
setContentView(R.layout.activity_downloader);
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
// its ok if this fails, we will catch that error later, and send it as report
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
if (actionBar != null) {
|
||||||
actionBar.setTitle(R.string.downloads_title);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setDisplayShowTitleEnabled(true);
|
actionBar.setTitle(R.string.downloads_title);
|
||||||
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
@@ -159,7 +158,7 @@ public class DownloadActivity extends AppCompatActivity implements AdapterView.O
|
|||||||
name.setText(getIntent().getStringExtra("fileName"));
|
name.setText(getIntent().getStringExtra("fileName"));
|
||||||
|
|
||||||
toolbar.setTitle(R.string.add);
|
toolbar.setTitle(R.string.add);
|
||||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp);
|
toolbar.setNavigationIcon(ThemeHelper.isLightThemeSelected(this) ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
|
||||||
toolbar.inflateMenu(R.menu.dialog_url);
|
toolbar.inflateMenu(R.menu.dialog_url);
|
||||||
|
|
||||||
// Show the dialog
|
// Show the dialog
|
||||||
@@ -183,7 +182,7 @@ public class DownloadActivity extends AppCompatActivity implements AdapterView.O
|
|||||||
if (item.getItemId() == R.id.okay) {
|
if (item.getItemId() == R.id.okay) {
|
||||||
|
|
||||||
String location;
|
String location;
|
||||||
if(audioButton.isChecked()) {
|
if (audioButton.isChecked()) {
|
||||||
location = NewPipeSettings.getAudioDownloadPath(DownloadActivity.this);
|
location = NewPipeSettings.getAudioDownloadPath(DownloadActivity.this);
|
||||||
} else {
|
} else {
|
||||||
location = NewPipeSettings.getVideoDownloadPath(DownloadActivity.this);
|
location = NewPipeSettings.getVideoDownloadPath(DownloadActivity.this);
|
||||||
@@ -201,7 +200,7 @@ public class DownloadActivity extends AppCompatActivity implements AdapterView.O
|
|||||||
audioButton.isChecked(), threads.getProgress() + 1);
|
audioButton.isChecked(), threads.getProgress() + 1);
|
||||||
mFragment.notifyChange();
|
mFragment.notifyChange();
|
||||||
|
|
||||||
mPrefs.edit().putInt(THREADS, threads.getProgress() + 1).commit();
|
mPrefs.edit().putInt(THREADS, threads.getProgress() + 1).apply();
|
||||||
mPendingUrl = null;
|
mPendingUrl = null;
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
package org.schabi.newpipe.download;
|
package org.schabi.newpipe.download;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
@@ -26,34 +23,32 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.schabi.newpipe.App;
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadManager;
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 21.09.15.
|
* Created by Christian Schabesberger on 21.09.15.
|
||||||
*
|
* <p>
|
||||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
* DownloadDialog.java is part of NewPipe.
|
* DownloadDialog.java is part of NewPipe.
|
||||||
*
|
* <p>
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
* <p>
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
* <p>
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@@ -71,8 +66,7 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DownloadDialog newInstance(Bundle args)
|
public static DownloadDialog newInstance(Bundle args) {
|
||||||
{
|
|
||||||
DownloadDialog dialog = new DownloadDialog();
|
DownloadDialog dialog = new DownloadDialog();
|
||||||
dialog.setArguments(args);
|
dialog.setArguments(args);
|
||||||
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
|
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
|
||||||
@@ -100,7 +94,7 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
final SeekBar threads = (SeekBar) view.findViewById(R.id.threads);
|
final SeekBar threads = (SeekBar) view.findViewById(R.id.threads);
|
||||||
|
|
||||||
toolbar.setTitle(R.string.download_dialog_title);
|
toolbar.setTitle(R.string.download_dialog_title);
|
||||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp);
|
toolbar.setNavigationIcon(ThemeHelper.isLightThemeSelected(getActivity()) ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
|
||||||
toolbar.inflateMenu(R.menu.dialog_url);
|
toolbar.inflateMenu(R.menu.dialog_url);
|
||||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -151,16 +145,16 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkDownloadOptions(){
|
protected void checkDownloadOptions() {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
Bundle arguments = getArguments();
|
Bundle arguments = getArguments();
|
||||||
RadioButton audioButton = (RadioButton) view.findViewById(R.id.audio_button);
|
RadioButton audioButton = (RadioButton) view.findViewById(R.id.audio_button);
|
||||||
RadioButton videoButton = (RadioButton) view.findViewById(R.id.video_button);
|
RadioButton videoButton = (RadioButton) view.findViewById(R.id.video_button);
|
||||||
|
|
||||||
if(arguments.getString(AUDIO_URL) == null) {
|
if (arguments.getString(AUDIO_URL) == null) {
|
||||||
audioButton.setVisibility(View.GONE);
|
audioButton.setVisibility(View.GONE);
|
||||||
videoButton.setChecked(true);
|
videoButton.setChecked(true);
|
||||||
} else if(arguments.getString(VIDEO_URL) == null) {
|
} else if (arguments.getString(VIDEO_URL) == null) {
|
||||||
videoButton.setVisibility(View.GONE);
|
videoButton.setVisibility(View.GONE);
|
||||||
audioButton.setChecked(true);
|
audioButton.setChecked(true);
|
||||||
}
|
}
|
||||||
@@ -169,11 +163,11 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
/**
|
/**
|
||||||
* #143 #44 #42 #22: make shure that the filename does not contain illegal chars.
|
* #143 #44 #42 #22: make shure that the filename does not contain illegal chars.
|
||||||
* This should fix some of the "cannot download" problems.
|
* This should fix some of the "cannot download" problems.
|
||||||
* */
|
*/
|
||||||
private String createFileName(String fName) {
|
private String createFileName(String fName) {
|
||||||
// from http://eng-przemelek.blogspot.de/2009/07/how-to-create-valid-file-name.html
|
// from http://eng-przemelek.blogspot.de/2009/07/how-to-create-valid-file-name.html
|
||||||
|
|
||||||
List<String> forbiddenCharsPatterns = new ArrayList<> ();
|
List<String> forbiddenCharsPatterns = new ArrayList<>();
|
||||||
forbiddenCharsPatterns.add("[:]+"); // Mac OS, but it looks that also Windows XP
|
forbiddenCharsPatterns.add("[:]+"); // Mac OS, but it looks that also Windows XP
|
||||||
forbiddenCharsPatterns.add("[\\*\"/\\\\\\[\\]\\:\\;\\|\\=\\,]+"); // Windows
|
forbiddenCharsPatterns.add("[\\*\"/\\\\\\[\\]\\:\\;\\|\\=\\,]+"); // Windows
|
||||||
forbiddenCharsPatterns.add("[^\\w\\d\\.]+"); // last chance... only latin letters and digits
|
forbiddenCharsPatterns.add("[^\\w\\d\\.]+"); // last chance... only latin letters and digits
|
||||||
@@ -186,8 +180,7 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
|
|
||||||
|
|
||||||
//download audio, video or both?
|
//download audio, video or both?
|
||||||
private void download()
|
private void download() {
|
||||||
{
|
|
||||||
View view = getView();
|
View view = getView();
|
||||||
Bundle arguments = getArguments();
|
Bundle arguments = getArguments();
|
||||||
final EditText name = (EditText) view.findViewById(R.id.file_name);
|
final EditText name = (EditText) view.findViewById(R.id.file_name);
|
||||||
@@ -199,7 +192,7 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
|
|
||||||
boolean isAudio = audioButton.isChecked();
|
boolean isAudio = audioButton.isChecked();
|
||||||
String url, location, filename;
|
String url, location, filename;
|
||||||
if(isAudio) {
|
if (isAudio) {
|
||||||
url = arguments.getString(AUDIO_URL);
|
url = arguments.getString(AUDIO_URL);
|
||||||
location = NewPipeSettings.getAudioDownloadPath(getContext());
|
location = NewPipeSettings.getAudioDownloadPath(getContext());
|
||||||
filename = fName + arguments.getString(FILE_SUFFIX_AUDIO);
|
filename = fName + arguments.getString(FILE_SUFFIX_AUDIO);
|
||||||
@@ -218,11 +211,11 @@ public class DownloadDialog extends DialogFragment {
|
|||||||
private void download(String url, String title,
|
private void download(String url, String title,
|
||||||
String fileSuffix, File downloadDir, Context context) {
|
String fileSuffix, File downloadDir, Context context) {
|
||||||
|
|
||||||
File saveFilePath = new File(downloadDir,createFileName(title) + fileSuffix);
|
File saveFilePath = new File(downloadDir, createFileName(title) + fileSuffix);
|
||||||
|
|
||||||
long id = 0;
|
long id = 0;
|
||||||
|
|
||||||
Log.i(TAG,"Started downloading '" + url +
|
Log.i(TAG, "Started downloading '" + url +
|
||||||
"' => '" + saveFilePath + "' #" + id);
|
"' => '" + saveFilePath + "' #" + id);
|
||||||
|
|
||||||
if (App.isUsingTor()) {
|
if (App.isUsingTor()) {
|
||||||
|
Submodule app/src/main/java/org/schabi/newpipe/extractor updated: 9005105e52...5907c35dfb
179
app/src/main/java/org/schabi/newpipe/fragments/BaseFragment.java
Normal file
179
app/src/main/java/org/schabi/newpipe/fragments/BaseFragment.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.AttrRes;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.view.ViewCompat;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
|
public abstract class BaseFragment extends Fragment {
|
||||||
|
protected final String TAG = "BaseFragment@" + Integer.toHexString(hashCode());
|
||||||
|
protected static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
|
protected AppCompatActivity activity;
|
||||||
|
protected OnItemSelectedListener onItemSelectedListener;
|
||||||
|
|
||||||
|
protected AtomicBoolean isLoading = new AtomicBoolean(false);
|
||||||
|
protected AtomicBoolean wasLoading = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
protected static final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
|
protected static final DisplayImageOptions displayImageOptions =
|
||||||
|
new DisplayImageOptions.Builder().displayer(new FadeInBitmapDisplayer(400)).cacheInMemory(false).build();
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Views
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected Toolbar toolbar;
|
||||||
|
|
||||||
|
protected View errorPanel;
|
||||||
|
protected Button errorButtonRetry;
|
||||||
|
protected TextView errorTextView;
|
||||||
|
protected ProgressBar loadingProgressBar;
|
||||||
|
//protected SwipeRefreshLayout swipeRefreshLayout;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment's Lifecycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (DEBUG) Log.d(TAG, "onAttach() called with: context = [" + context + "]");
|
||||||
|
|
||||||
|
activity = (AppCompatActivity) context;
|
||||||
|
onItemSelectedListener = (OnItemSelectedListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
|
||||||
|
isLoading.set(false);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View rootView, Bundle savedInstanceState) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onViewCreated() called with: rootView = [" + rootView + "], savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
initViews(rootView, savedInstanceState);
|
||||||
|
initListeners();
|
||||||
|
wasLoading.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
if (DEBUG) Log.d(TAG, "onDestroyView() called");
|
||||||
|
toolbar = null;
|
||||||
|
|
||||||
|
errorPanel = null;
|
||||||
|
errorButtonRetry = null;
|
||||||
|
errorTextView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Init
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
|
toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
|
||||||
|
|
||||||
|
loadingProgressBar = (ProgressBar) rootView.findViewById(R.id.loading_progress_bar);
|
||||||
|
//swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh);
|
||||||
|
|
||||||
|
errorPanel = rootView.findViewById(R.id.error_panel);
|
||||||
|
errorButtonRetry = (Button) rootView.findViewById(R.id.error_button_retry);
|
||||||
|
errorTextView = (TextView) rootView.findViewById(R.id.error_message_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initListeners() {
|
||||||
|
errorButtonRetry.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onRetryButtonClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void reloadContent();
|
||||||
|
|
||||||
|
protected void onRetryButtonClicked() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onRetryButtonClicked() called");
|
||||||
|
reloadContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected void setErrorMessage(String message, boolean showRetryButton) {
|
||||||
|
if (errorTextView == null || activity == null) return;
|
||||||
|
|
||||||
|
errorTextView.setText(message);
|
||||||
|
if (showRetryButton) animateView(errorButtonRetry, true, 300);
|
||||||
|
else animateView(errorButtonRetry, false, 0);
|
||||||
|
|
||||||
|
animateView(errorPanel, true, 300);
|
||||||
|
isLoading.set(false);
|
||||||
|
|
||||||
|
animateView(loadingProgressBar, false, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getResourceIdFromAttr(@AttrRes int attr) {
|
||||||
|
TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{attr});
|
||||||
|
int attributeResourceId = a.getResourceId(0, 0);
|
||||||
|
a.recycle();
|
||||||
|
return attributeResourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showMenuTooltip(View v, String message) {
|
||||||
|
final int[] screenPos = new int[2];
|
||||||
|
final Rect displayFrame = new Rect();
|
||||||
|
v.getLocationOnScreen(screenPos);
|
||||||
|
v.getWindowVisibleDisplayFrame(displayFrame);
|
||||||
|
|
||||||
|
final Context context = v.getContext();
|
||||||
|
final int width = v.getWidth();
|
||||||
|
final int height = v.getHeight();
|
||||||
|
final int midy = screenPos[1] + height / 2;
|
||||||
|
int referenceX = screenPos[0] + width / 2;
|
||||||
|
if (ViewCompat.getLayoutDirection(v) == View.LAYOUT_DIRECTION_LTR) {
|
||||||
|
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||||
|
referenceX = screenWidth - referenceX; // mirror
|
||||||
|
}
|
||||||
|
Toast cheatSheet = Toast.makeText(context, message, Toast.LENGTH_SHORT);
|
||||||
|
if (midy < displayFrame.height()) {
|
||||||
|
// Show along the top; follow action buttons
|
||||||
|
cheatSheet.setGravity(Gravity.TOP | Gravity.END, referenceX,
|
||||||
|
screenPos[1] + height - displayFrame.top);
|
||||||
|
} else {
|
||||||
|
// Show along the bottom center
|
||||||
|
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
|
||||||
|
}
|
||||||
|
cheatSheet.show();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
|
public class MainFragment extends Fragment {
|
||||||
|
private final String TAG = "MainFragment@" + Integer.toHexString(hashCode());
|
||||||
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
|
private AppCompatActivity activity;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment's LifeCycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (DEBUG) Log.d(TAG, "onAttach() called with: context = [" + context + "]");
|
||||||
|
activity = ((AppCompatActivity) context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onCreateView() called with: inflater = [" + inflater + "], container = [" + container + "], savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
|
||||||
|
inflater.inflate(R.menu.main_fragment_menu, menu);
|
||||||
|
|
||||||
|
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
|
if (supportActionBar != null) {
|
||||||
|
supportActionBar.setDisplayShowTitleEnabled(false);
|
||||||
|
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.action_search:
|
||||||
|
NavigationHelper.openSearch(activity, 0, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for communication purposes between activity and fragment
|
||||||
|
*/
|
||||||
|
public interface OnItemSelectedListener {
|
||||||
|
void onItemSelected(StreamingService.LinkType linkType, int serviceId, String url, String name);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
|||||||
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
||||||
|
import org.schabi.newpipe.util.Utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Christian Schabesberger on 18.08.15.
|
||||||
|
* <p>
|
||||||
|
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||||
|
* DetailsMenuHandler.java is part of NewPipe.
|
||||||
|
* <p>
|
||||||
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* <p>
|
||||||
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* <p>
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
class ActionBarHandler {
|
||||||
|
private static final String TAG = "ActionBarHandler";
|
||||||
|
|
||||||
|
private AppCompatActivity activity;
|
||||||
|
private int selectedVideoStream = -1;
|
||||||
|
|
||||||
|
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 VideoDetailFragment will implement those callbacks.
|
||||||
|
private OnActionListener onShareListener;
|
||||||
|
private OnActionListener onOpenInBrowserListener;
|
||||||
|
private OnActionListener onDownloadListener;
|
||||||
|
private OnActionListener onPlayWithKodiListener;
|
||||||
|
|
||||||
|
// Triggered when a stream related action is triggered.
|
||||||
|
public interface OnActionListener {
|
||||||
|
void onActionSelected(int selectedStreamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionBarHandler(AppCompatActivity activity) {
|
||||||
|
this.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupStreamList(final List<VideoStream> videoStreams, Spinner toolbarSpinner) {
|
||||||
|
if (activity == null) return;
|
||||||
|
selectedVideoStream = 0;
|
||||||
|
|
||||||
|
// this array will be shown in the dropdown menu for selecting the stream/resolution.
|
||||||
|
String[] itemArray = new String[videoStreams.size()];
|
||||||
|
for (int i = 0; i < videoStreams.size(); i++) {
|
||||||
|
VideoStream item = videoStreams.get(i);
|
||||||
|
itemArray[i] = MediaFormat.getNameById(item.format) + " " + item.resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
int defaultResolutionIndex = Utils.getDefaultResolution(activity, videoStreams);
|
||||||
|
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(activity.getBaseContext(), android.R.layout.simple_spinner_dropdown_item, itemArray);
|
||||||
|
toolbarSpinner.setAdapter(itemAdapter);
|
||||||
|
toolbarSpinner.setSelection(defaultResolutionIndex);
|
||||||
|
toolbarSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
selectedVideoStream = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> parent) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
this.menu = menu;
|
||||||
|
|
||||||
|
// CAUTION set item properties programmatically otherwise it would not be accepted by
|
||||||
|
// appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
|
||||||
|
|
||||||
|
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
|
inflater.inflate(R.menu.video_detail_menu, menu);
|
||||||
|
|
||||||
|
updateItemsVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateItemsVisibility(){
|
||||||
|
showPlayWithKodiAction(defaultPreferences.getBoolean(activity.getString(R.string.show_play_with_kodi_key), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
switch (id) {
|
||||||
|
case R.id.menu_item_share: {
|
||||||
|
if (onShareListener != null) {
|
||||||
|
onShareListener.onActionSelected(selectedVideoStream);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.menu_item_openInBrowser: {
|
||||||
|
if (onOpenInBrowserListener != null) {
|
||||||
|
onOpenInBrowserListener.onActionSelected(selectedVideoStream);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.menu_item_download:
|
||||||
|
if (onDownloadListener != null) {
|
||||||
|
onDownloadListener.onActionSelected(selectedVideoStream);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case R.id.action_play_with_kodi:
|
||||||
|
if (onPlayWithKodiListener != null) {
|
||||||
|
onPlayWithKodiListener.onActionSelected(selectedVideoStream);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Menu Item not known");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedVideoStream() {
|
||||||
|
return selectedVideoStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnShareListener(OnActionListener listener) {
|
||||||
|
onShareListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnOpenInBrowserListener(OnActionListener listener) {
|
||||||
|
onOpenInBrowserListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnDownloadListener(OnActionListener listener) {
|
||||||
|
onDownloadListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnPlayWithKodiListener(OnActionListener listener) {
|
||||||
|
onPlayWithKodiListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showDownloadAction(boolean visible) {
|
||||||
|
menu.findItem(R.id.menu_item_download).setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showPlayWithKodiAction(boolean visible) {
|
||||||
|
menu.findItem(R.id.action_play_with_kodi).setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class StackItem implements Serializable {
|
||||||
|
private String title, url;
|
||||||
|
private StreamInfo info;
|
||||||
|
|
||||||
|
public StackItem(String url, String title) {
|
||||||
|
this.title = title;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(StreamInfo info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamInfo getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getUrl() + " > " + getTitle();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,85 @@
|
|||||||
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class StreamInfoCache {
|
||||||
|
private static String TAG = "StreamInfoCache@";
|
||||||
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
private static final StreamInfoCache instance = new StreamInfoCache();
|
||||||
|
private static final int MAX_ITEMS_ON_CACHE = 20;
|
||||||
|
|
||||||
|
private final LinkedHashMap<String, StreamInfo> myCache = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
private StreamInfoCache() {
|
||||||
|
TAG += "" + Integer.toHexString(hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StreamInfoCache getInstance() {
|
||||||
|
if (DEBUG) Log.d(TAG, "getInstance() called");
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasKey(@NonNull String url) {
|
||||||
|
if (DEBUG) Log.d(TAG, "hasKey() called with: url = [" + url + "]");
|
||||||
|
return !TextUtils.isEmpty(url) && myCache.containsKey(url) && myCache.get(url) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamInfo getFromKey(@NonNull String url) {
|
||||||
|
if (DEBUG) Log.d(TAG, "getFromKey() called with: url = [" + url + "]");
|
||||||
|
return myCache.get(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putInfo(@NonNull StreamInfo info) {
|
||||||
|
if (DEBUG) Log.d(TAG, "putInfo() called with: info = [" + info + "]");
|
||||||
|
putInfo(info.webpage_url, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putInfo(@NonNull String url, @NonNull StreamInfo info) {
|
||||||
|
if (DEBUG) Log.d(TAG, "putInfo() called with: url = [" + url + "], info = [" + info + "]");
|
||||||
|
myCache.put(url, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeInfo(@NonNull StreamInfo info) {
|
||||||
|
if (DEBUG) Log.d(TAG, "removeInfo() called with: info = [" + info + "]");
|
||||||
|
myCache.remove(info.webpage_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeInfo(@NonNull String url) {
|
||||||
|
if (DEBUG) Log.d(TAG, "removeInfo() called with: url = [" + url + "]");
|
||||||
|
myCache.remove(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void clearCache() {
|
||||||
|
if (DEBUG) Log.d(TAG, "clearCache() called");
|
||||||
|
myCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOldEntries() {
|
||||||
|
if (DEBUG) Log.d(TAG, "removeOldEntries() called , size = " + getSize());
|
||||||
|
if (getSize() > MAX_ITEMS_ON_CACHE) {
|
||||||
|
Iterator<String> iterator = myCache.keySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
iterator.next();
|
||||||
|
iterator.remove();
|
||||||
|
if (DEBUG) Log.d(TAG, "getSize() = " + getSize());
|
||||||
|
if (getSize() <= MAX_ITEMS_ON_CACHE) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return myCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
package org.schabi.newpipe.search_fragment;
|
package org.schabi.newpipe.fragments.search;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@@ -75,6 +75,11 @@ public class SuggestionListAdapter extends ResourceCursorAdapter {
|
|||||||
return ((Cursor) getItem(position)).getString(INDEX_TITLE);
|
return ((Cursor) getItem(position)).getString(INDEX_TITLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence convertToString(Cursor cursor) {
|
||||||
|
return cursor.getString(INDEX_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
private class ViewHolder {
|
private class ViewHolder {
|
||||||
private final TextView suggestionTitle;
|
private final TextView suggestionTitle;
|
||||||
private ViewHolder(View view) {
|
private ViewHolder(View view) {
|
@@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe.info_list;
|
package org.schabi.newpipe.info_list;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
@@ -35,16 +34,17 @@ public class ChannelInfoItemHolder extends InfoItemHolder {
|
|||||||
public final TextView itemSubscriberCountView;
|
public final TextView itemSubscriberCountView;
|
||||||
public final TextView itemVideoCountView;
|
public final TextView itemVideoCountView;
|
||||||
public final TextView itemChannelDescriptionView;
|
public final TextView itemChannelDescriptionView;
|
||||||
public final Button itemButton;
|
|
||||||
|
public final View itemRoot;
|
||||||
|
|
||||||
ChannelInfoItemHolder(View v) {
|
ChannelInfoItemHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
itemRoot = v.findViewById(R.id.itemRoot);
|
||||||
itemThumbnailView = (CircleImageView) v.findViewById(R.id.itemThumbnailView);
|
itemThumbnailView = (CircleImageView) v.findViewById(R.id.itemThumbnailView);
|
||||||
itemChannelTitleView = (TextView) v.findViewById(R.id.itemChannelTitleView);
|
itemChannelTitleView = (TextView) v.findViewById(R.id.itemChannelTitleView);
|
||||||
itemSubscriberCountView = (TextView) v.findViewById(R.id.itemSubscriberCountView);
|
itemSubscriberCountView = (TextView) v.findViewById(R.id.itemSubscriberCountView);
|
||||||
itemVideoCountView = (TextView) v.findViewById(R.id.itemVideoCountView);
|
itemVideoCountView = (TextView) v.findViewById(R.id.itemVideoCountView);
|
||||||
itemChannelDescriptionView = (TextView) v.findViewById(R.id.itemChannelDescriptionView);
|
itemChannelDescriptionView = (TextView) v.findViewById(R.id.itemChannelDescriptionView);
|
||||||
itemButton = (Button) v.findViewById(R.id.item_button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
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