mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-09-23 09:20:51 +02:00
Compare commits
115 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c4ea73ca7a | ||
![]() |
2aa28d6453 | ||
![]() |
2d51085ccf | ||
![]() |
4eae02e47e | ||
![]() |
f3bf9f9e5d | ||
![]() |
75d0b84bdb | ||
![]() |
3643ddcf5c | ||
![]() |
35500e8ef7 | ||
![]() |
6badcf5391 | ||
![]() |
d4898043f6 | ||
![]() |
2322ba833a | ||
![]() |
5aabb2917f | ||
![]() |
eacbf6ce50 | ||
![]() |
031300a132 | ||
![]() |
f905611e69 | ||
![]() |
e475f9f876 | ||
![]() |
b65263349e | ||
![]() |
5cb8026f6d | ||
![]() |
cc7ce5cf93 | ||
![]() |
af506639a9 | ||
![]() |
d377d67174 | ||
![]() |
cf926353d1 | ||
![]() |
d686c744d0 | ||
![]() |
501c60b180 | ||
![]() |
da36687e25 | ||
![]() |
f13f9a066a | ||
![]() |
8eaa4f7654 | ||
![]() |
145a7f8e0d | ||
![]() |
67ba126602 | ||
![]() |
c5084901b5 | ||
![]() |
3bfc82f7c0 | ||
![]() |
3411b53450 | ||
![]() |
873564f2aa | ||
![]() |
353ed90d12 | ||
![]() |
799faecc5b | ||
![]() |
731321b1f9 | ||
![]() |
7ff43caf96 | ||
![]() |
d0877c3132 | ||
![]() |
c589b03dcb | ||
![]() |
862b5aaef6 | ||
![]() |
596443bf5e | ||
![]() |
27b450f1e3 | ||
![]() |
61a09e97ca | ||
![]() |
224e7a8969 | ||
![]() |
9e7d9ee973 | ||
![]() |
586bad345c | ||
![]() |
abdd7dc7d3 | ||
![]() |
aee32f7a3e | ||
![]() |
696760e65a | ||
![]() |
200db15d4b | ||
![]() |
33e332f105 | ||
![]() |
bb2955e442 | ||
![]() |
2fc2fa56c3 | ||
![]() |
c87458590c | ||
![]() |
8aff134c56 | ||
![]() |
4a938b81df | ||
![]() |
4def715b25 | ||
![]() |
821acf12d8 | ||
![]() |
fc707b6c7e | ||
![]() |
85ac000479 | ||
![]() |
68a0eefa20 | ||
![]() |
fc32377ce7 | ||
![]() |
59e512a64d | ||
![]() |
c51a5a51f1 | ||
![]() |
9546a276dc | ||
![]() |
a18353df5f | ||
![]() |
3c72113f4c | ||
![]() |
7e193751c4 | ||
![]() |
56c96eb712 | ||
![]() |
4106a984ca | ||
![]() |
10f1ab0598 | ||
![]() |
bca9603440 | ||
![]() |
c32c267889 | ||
![]() |
627e987bda | ||
![]() |
7c18e147f3 | ||
![]() |
6a8fb5910d | ||
![]() |
b865326d51 | ||
![]() |
a2d5b0893d | ||
![]() |
db0508b9ab | ||
![]() |
1850dee93a | ||
![]() |
7b1eb8a6dc | ||
![]() |
95a9f2f5e3 | ||
![]() |
ae7ed2d226 | ||
![]() |
20cf82bab1 | ||
![]() |
5dcb1e26b5 | ||
![]() |
8076589180 | ||
![]() |
edbd4003be | ||
![]() |
122b089bf0 | ||
![]() |
a28d917990 | ||
![]() |
5b605a1100 | ||
![]() |
f67158a2a7 | ||
![]() |
c22c2009d4 | ||
![]() |
ab4d626ea9 | ||
![]() |
96709d22e9 | ||
![]() |
f0bd171eee | ||
![]() |
c4191077f3 | ||
![]() |
321d090052 | ||
![]() |
32dcb4d281 | ||
![]() |
080159849e | ||
![]() |
d9e690f62c | ||
![]() |
8c0156dea3 | ||
![]() |
038c59ce66 | ||
![]() |
72e08c0447 | ||
![]() |
173eaa8cf8 | ||
![]() |
a04cd24e5e | ||
![]() |
0e11404b3b | ||
![]() |
342807e26a | ||
![]() |
c068f08ff8 | ||
![]() |
b7c0a77edc | ||
![]() |
aab0f45890 | ||
![]() |
c62ad66f11 | ||
![]() |
d8bdada9db | ||
![]() |
1b9f7a7654 | ||
![]() |
ac710fff08 | ||
![]() |
2e09492eef |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,7 +1,8 @@
|
||||
.gitignore
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
/app/app.iml
|
||||
/.idea
|
||||
|
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
NewPipe
|
22
.idea/compiler.xml
generated
22
.idea/compiler.xml
generated
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
3
.idea/dictionaries/the_scrabi.xml
generated
3
.idea/dictionaries/the_scrabi.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="the-scrabi" />
|
||||
</component>
|
19
.idea/gradle.xml
generated
19
.idea/gradle.xml
generated
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="LOCAL" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.4" />
|
||||
<option name="gradleJvm" value="1.8" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
46
.idea/misc.xml
generated
46
.idea/misc.xml
generated
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
9
.idea/modules.xml
generated
9
.idea/modules.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/NewPipe.iml" filepath="$PROJECT_DIR$/NewPipe.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/runConfigurations.xml
generated
12
.idea/runConfigurations.xml
generated
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
19
NewPipe.iml
19
NewPipe.iml
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="NewPipe" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||
<option name="BUILDABLE" value="false" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
47
README.md
47
README.md
@@ -1,7 +1,46 @@
|
||||
NewPipe
|
||||
-------
|
||||
# NewPipe
|
||||
|
||||
[](https://hosted.weblate.org/engage/NewPipe/)
|
||||
|
||||
NewPipe is a lightweight youtube frontend for android. It's supposed to be used without the youtube-api and without any google play services. NewPipe only parses the youtube website in order to gain the information it needs.
|
||||
[](http://dasochan.nl/newpipe/)
|
||||
NewPipe: A free lightweight Youtube frontend for Android.
|
||||
|
||||
This a very early version of the app, so not all functionality is implemented, and there may still be a lot of bugs. But all in all it's doing what it is supposed to do. It makes it possible to watch youtube videos. So don't be cruel to this app. It will improve...
|
||||
[](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe)
|
||||
|
||||
## Description
|
||||
|
||||
NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without G-services installed. Also NewPipe does not store data on the YouTube website (no login), and it's free software.
|
||||
|
||||
## Features
|
||||
|
||||
* Search videos
|
||||
* Display general information about a video
|
||||
* Watch Youtube videos
|
||||
* Listen to Youtube videos (audio only streaming)
|
||||
* Select the streaming player to watch the video with
|
||||
* Download videos (working, but it could be better)
|
||||
* Download audio only (working but, but it could be better)
|
||||
* Open a video in Kodi
|
||||
* Show Next/Related videos
|
||||
* Search Youtube in a specific language
|
||||
|
||||
## Coming Features
|
||||
|
||||
* Improved Downloading
|
||||
* Bookmarks
|
||||
* View history
|
||||
* Search history
|
||||
* Search channels
|
||||
* Display general information about channels
|
||||
* Subscribe to channels
|
||||
* Watch videos from a channel
|
||||
* Search/Watch Playlists
|
||||
* ... and many more
|
||||
|
||||
### Multi service support
|
||||
Generally NewPipe is designed to not only support YouTube, but many more streaming services. However, right now NewPipe is not stable enough to support more than only YouTube. But if all works as planned, NewPipe will get such support by the version 2.0.
|
||||
|
||||
# Help is always welcome !!!
|
||||
Whether it's about ideas, translation, design changes, code cleaning, or real heavy code changes. Help is always welcome.
|
||||
|
||||
The more is done the better it gets!
|
||||
|
2
app/.gitignore
vendored
2
app/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
.gitignore
|
||||
/build
|
||||
app.iml
|
||||
|
101
app/app.iml
101
app/app.iml
@@ -1,101 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="NewPipe" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
||||
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugAndroidTestSources</task>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.0.1/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="jsoup-1.8.3" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="rhino-1.7.7" level="project" />
|
||||
<orderEntry type="library" exported="" name="design-23.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
|
||||
</component>
|
||||
</module>
|
@@ -8,8 +8,8 @@ android {
|
||||
applicationId "org.schabi.newpipe"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 4
|
||||
versionName "0.4.1"
|
||||
versionCode 6
|
||||
versionName "0.6.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -21,9 +21,9 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
compile 'com.android.support:appcompat-v7:23.0.1'
|
||||
compile 'com.android.support:support-v4:23.0.1'
|
||||
compile 'com.android.support:appcompat-v7:23.1.0'
|
||||
compile 'com.android.support:support-v4:23.1.0'
|
||||
compile 'com.android.support:design:23.1.0'
|
||||
compile 'org.jsoup:jsoup:1.8.3'
|
||||
compile 'org.mozilla:rhino:1.7.7'
|
||||
compile 'com.android.support:design:23.0.1'
|
||||
}
|
||||
|
@@ -34,27 +34,27 @@
|
||||
<data
|
||||
android:host="youtube.com"
|
||||
android:scheme="http"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="youtube.com"
|
||||
android:scheme="https"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="www.youtube.com"
|
||||
android:scheme="http"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="www.youtube.com"
|
||||
android:scheme="https"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="m.youtube.com"
|
||||
android:scheme="http"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="m.youtube.com"
|
||||
android:scheme="https"
|
||||
android:pathPrefix="/watch"/>
|
||||
android:pathPattern="/?*#*/*watch"/>
|
||||
<data
|
||||
android:host="youtu.be"
|
||||
android:scheme="https"
|
||||
@@ -68,6 +68,7 @@
|
||||
<activity android:name=".PlayVideoActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/FullscreenTheme"
|
||||
android:parentActivityName=".VideoItemDetailActivity"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 14.08.15.
|
||||
@@ -28,12 +30,25 @@ import java.net.URL;
|
||||
public class Downloader {
|
||||
|
||||
private static final String USER_AGENT = "Mozilla/5.0";
|
||||
public static String download(String siteUrl) {
|
||||
|
||||
StringBuffer response = new StringBuffer();
|
||||
public static String download(String siteUrl, String language) {
|
||||
String ret = "";
|
||||
try {
|
||||
URL url = new URL(siteUrl);
|
||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||
con.setRequestProperty("Accept-Language", language);
|
||||
ret = dl(con);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static String dl(HttpURLConnection con) {
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
try {
|
||||
con.setRequestMethod("GET");
|
||||
con.setRequestProperty("User-Agent", USER_AGENT);
|
||||
|
||||
@@ -45,9 +60,31 @@ public class Downloader {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
catch(UnknownHostException uhe) {//thrown when there's no internet connection
|
||||
uhe.printStackTrace();
|
||||
//Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return response.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String download(String siteUrl) {
|
||||
String ret = "";
|
||||
|
||||
try {
|
||||
URL url = new URL(siteUrl);
|
||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||
ret = dl(con);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 10.08.15.
|
||||
*
|
||||
|
64
app/src/main/java/org/schabi/newpipe/MediaFormat.java
Normal file
64
app/src/main/java/org/schabi/newpipe/MediaFormat.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
/**
|
||||
* Created by Adam Howard on 08/11/15.
|
||||
*
|
||||
* Copyright (c) Christian Schabesberger <chris.schabesberger@mailbox.org>
|
||||
* and Adam Howard <achdisposable1@gmail.com> 2015
|
||||
*
|
||||
* VideoListAdapter.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
public enum MediaFormat {
|
||||
// id name suffix mime type
|
||||
MPEG_4 (0x0, "MPEG-4", "mp4", "video/mp4"),
|
||||
v3GPP (0x1, "3GPP", "3gp", "video/3gpp"),
|
||||
WEBM (0x2, "WebM", "webm", "video/webm"),
|
||||
M4A (0x3, "m4a", "m4a", "audio/mp4"),
|
||||
WEBMA (0x4, "WebM", "webm", "audio/webm");
|
||||
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final String suffix;
|
||||
public final String mimeType;
|
||||
|
||||
MediaFormat(int id, String name, String suffix, String mimeType) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.suffix = suffix;
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public static String getNameById(int ident) {
|
||||
for (MediaFormat vf : MediaFormat.values()) {
|
||||
if(vf.id == ident) return vf.name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getSuffixById(int ident) {
|
||||
for (MediaFormat vf : MediaFormat.values()) {
|
||||
if(vf.id == ident) return vf.suffix;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getMimeById(int ident) {
|
||||
for (MediaFormat vf : MediaFormat.values()) {
|
||||
if(vf.id == ident) return vf.mimeType;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -17,15 +18,11 @@ import android.view.Display;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.MediaController;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.VideoView;
|
||||
|
||||
/**
|
||||
@@ -72,6 +69,9 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
private boolean isLandscape = true;
|
||||
private boolean hasSoftKeys = false;
|
||||
|
||||
private SharedPreferences prefs;
|
||||
private static final String PREF_IS_LANDSCAPE = "is_landscape";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -79,7 +79,7 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
setContentView(R.layout.activity_play_video);
|
||||
|
||||
isLandscape = checkIfLandscape();
|
||||
hasSoftKeys = checkIfhasSoftKeys();
|
||||
hasSoftKeys = checkIfHasSoftKeys();
|
||||
|
||||
actionBar = getSupportActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
@@ -133,15 +133,21 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
}
|
||||
});
|
||||
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
if (android.os.Build.VERSION.SDK_INT >= 17) {
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
|
||||
prefs = getPreferences(Context.MODE_PRIVATE);
|
||||
if(prefs.getBoolean(PREF_IS_LANDSCAPE, false) && !isLandscape) {
|
||||
toggleOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -179,14 +185,7 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.shareDialogTitle)));
|
||||
break;
|
||||
case R.id.menu_item_screen_rotation:
|
||||
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
|
||||
if(display.getRotation() == Surface.ROTATION_0
|
||||
|| display.getRotation() == Surface.ROTATION_180) {
|
||||
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
} else if(display.getRotation() == Surface.ROTATION_90
|
||||
|| display.getRotation() == Surface.ROTATION_270) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
toggleOrientation();
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Error: MenuItem not known");
|
||||
@@ -201,10 +200,10 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
|
||||
if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
isLandscape = true;
|
||||
adjustMediaControllMetrics();
|
||||
adjustMediaControlMetrics();
|
||||
} else if (config.orientation == Configuration.ORIENTATION_PORTRAIT){
|
||||
isLandscape = false;
|
||||
adjustMediaControllMetrics();
|
||||
adjustMediaControlMetrics();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +226,7 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
uiIsHidden = false;
|
||||
mediaController.show(100000);
|
||||
actionBar.show();
|
||||
adjustMediaControllMetrics();
|
||||
adjustMediaControlMetrics();
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@@ -248,16 +247,18 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
uiIsHidden = true;
|
||||
actionBar.hide();
|
||||
mediaController.hide();
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
if (android.os.Build.VERSION.SDK_INT >= 17) {
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
private void adjustMediaControllMetrics() {
|
||||
private void adjustMediaControlMetrics() {
|
||||
MediaController.LayoutParams mediaControllerLayout
|
||||
= new MediaController.LayoutParams(MediaController.LayoutParams.MATCH_PARENT,
|
||||
MediaController.LayoutParams.WRAP_CONTENT);
|
||||
@@ -272,7 +273,7 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
mediaController.setLayoutParams(mediaControllerLayout);
|
||||
}
|
||||
|
||||
private boolean checkIfhasSoftKeys(){
|
||||
private boolean checkIfHasSoftKeys(){
|
||||
if(Build.VERSION.SDK_INT >= 17) {
|
||||
return getNavigationBarHeight() != 0 || getNavigationBarWidth() != 0;
|
||||
} else {
|
||||
@@ -319,4 +320,17 @@ public class PlayVideoActivity extends AppCompatActivity {
|
||||
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
return displayMetrics.heightPixels < displayMetrics.widthPixels;
|
||||
}
|
||||
|
||||
private void toggleOrientation() {
|
||||
if(isLandscape) {
|
||||
isLandscape = false;
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
} else {
|
||||
isLandscape = true;
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
}
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
@@ -33,5 +32,8 @@ public interface SearchEngine {
|
||||
public Vector<VideoInfoItem> resultList = new Vector<>();
|
||||
}
|
||||
|
||||
Result search(String query, int page);
|
||||
ArrayList<String> suggestionList(String query);
|
||||
|
||||
//Result search(String query, int page);
|
||||
Result search(String query, int page, String contentCountry);
|
||||
}
|
||||
|
@@ -25,11 +25,11 @@ public interface StreamingService {
|
||||
public String name = "";
|
||||
}
|
||||
ServiceInfo getServiceInfo();
|
||||
Class getExtractorClass();
|
||||
Class getSearchEngineClass();
|
||||
Extractor getExtractorInstance();
|
||||
SearchEngine getSearchEngineInstance();
|
||||
|
||||
// When a VIEW_ACTION is caught this function will test if the url delivered within the calling
|
||||
// Intent was meant to be watched with this Service.
|
||||
// Return false if this service shall not allow to be callean through ACTIONs.
|
||||
/**When a VIEW_ACTION is caught this function will test if the url delivered within the calling
|
||||
Intent was meant to be watched with this Service.
|
||||
Return false if this service shall not allow to be callean through ACTIONs.*/
|
||||
boolean acceptUrl(String videoUrl);
|
||||
}
|
||||
|
@@ -1,5 +1,11 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 26.08.15.
|
||||
*
|
||||
@@ -20,85 +26,36 @@ package org.schabi.newpipe;
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**Info object for opened videos, ie the video ready to play.*/
|
||||
public class VideoInfo {
|
||||
public String id = "";
|
||||
public String title = "";
|
||||
public String uploader = "";
|
||||
public String thumbnail_url = "";
|
||||
public Bitmap thumbnail = null;
|
||||
public String webpage_url = "";
|
||||
public String upload_date = "";
|
||||
public long view_count = 0;
|
||||
|
||||
public String uploader_thumbnail_url = "";
|
||||
public Bitmap uploader_thumbnail = null;
|
||||
public String description = "";
|
||||
public int duration = -1;
|
||||
public int age_limit = 0;
|
||||
public int like_count = 0;
|
||||
public int dislike_count = 0;
|
||||
public String average_rating = "";
|
||||
public VideoStream[] videoStreams = null;
|
||||
public AudioStream[] audioStreams = null;
|
||||
public VideoInfoItem nextVideo = null;
|
||||
public VideoInfoItem[] relatedVideos = null;
|
||||
public int videoAvailableStatus = VIDEO_AVAILABLE;
|
||||
|
||||
private static final String TAG = VideoInfo.class.toString();
|
||||
|
||||
// format identifier
|
||||
public static final int I_MPEG_4 = 0x0;
|
||||
public static final int I_3GPP = 0x1;
|
||||
public static final int I_WEBM = 0x2;
|
||||
public static final int I_M4A = 0x3;
|
||||
public static final int I_WEBMA = 0x4;
|
||||
|
||||
// format name
|
||||
public static final String F_MPEG_4 = "MPEG-4";
|
||||
public static final String F_3GPP = "3GPP";
|
||||
public static final String F_WEBM = "WebM";
|
||||
public static final String F_M4A = "m4a";
|
||||
public static final String F_WEBMA = "WebM";
|
||||
|
||||
// file suffix
|
||||
public static final String C_MPEG_4 = "mp4";
|
||||
public static final String C_3GPP = "3gp";
|
||||
public static final String C_WEBM = "webm";
|
||||
public static final String C_M4A = "m4a";
|
||||
public static final String C_WEBMA = "webm";
|
||||
|
||||
// mimeType
|
||||
public static final String M_MPEG_4 = "video/mp4";
|
||||
public static final String M_3GPP = "video/3gpp";
|
||||
public static final String M_WEBM = "video/webm";
|
||||
public static final String M_M4A = "audio/mp4";
|
||||
public static final String M_WEBMA = "audio/webm";
|
||||
|
||||
public static final int VIDEO_AVAILABLE = 0x00;
|
||||
public static final int VIDEO_UNAVAILABLE = 0x01;
|
||||
public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;
|
||||
|
||||
public static String getNameById(int id) {
|
||||
switch(id) {
|
||||
case I_MPEG_4: return F_MPEG_4;
|
||||
case I_3GPP: return F_3GPP;
|
||||
case I_WEBM: return F_WEBM;
|
||||
case I_M4A: return F_M4A;
|
||||
case I_WEBMA: return F_WEBMA;
|
||||
default: Log.e(TAG, "format not known: " +
|
||||
Integer.toString(id) + "call the programmer he messed it up.");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getSuffixById(int id) {
|
||||
switch(id) {
|
||||
case I_MPEG_4: return C_MPEG_4;
|
||||
case I_3GPP: return C_3GPP;
|
||||
case I_WEBM: return C_WEBM;
|
||||
case I_M4A: return C_M4A;
|
||||
case I_WEBMA: return C_WEBMA;
|
||||
default: Log.e(TAG, "format not known: " +
|
||||
Integer.toString(id) + "call the programmer he messed it up.");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getMimeById(int id) {
|
||||
switch(id) {
|
||||
case I_MPEG_4: return M_MPEG_4;
|
||||
case I_3GPP: return M_3GPP;
|
||||
case I_WEBM: return M_WEBM;
|
||||
case I_M4A: return M_M4A;
|
||||
case I_WEBMA: return M_WEBMA;
|
||||
default: Log.e(TAG, "format not known: " +
|
||||
Integer.toString(id) + "call the programmer he messed it up.");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;//German DRM organisation
|
||||
|
||||
public static class VideoStream {
|
||||
public VideoStream(String url, int format, String res) {
|
||||
@@ -110,36 +67,13 @@ public class VideoInfo {
|
||||
}
|
||||
|
||||
public static class AudioStream {
|
||||
public AudioStream(String url, int format, int bandWidth, int samplingRate) {
|
||||
public AudioStream(String url, int format, int bandwidth, int samplingRate) {
|
||||
this.url = url; this.format = format;
|
||||
this.bandWidth = bandWidth; this.samplingRate = samplingRate;
|
||||
this.bandwidth = bandwidth; this.samplingRate = samplingRate;
|
||||
}
|
||||
public String url = "";
|
||||
public int format = -1;
|
||||
public int bandWidth = -1;
|
||||
public int bandwidth = -1;
|
||||
public int samplingRate = -1;
|
||||
|
||||
}
|
||||
|
||||
public String id = "";
|
||||
public String uploader = "";
|
||||
public String upload_date = "";
|
||||
public String uploader_thumbnail_url = "";
|
||||
public Bitmap uploader_thumbnail = null;
|
||||
public String title = "";
|
||||
public String thumbnail_url = "";
|
||||
public Bitmap thumbnail = null;
|
||||
public String description = "";
|
||||
public int duration = -1;
|
||||
public int age_limit = 0;
|
||||
public String webpage_url = "";
|
||||
public String view_count = "";
|
||||
public String like_count = "";
|
||||
public String dislike_count = "";
|
||||
public String average_rating = "";
|
||||
public VideoStream[] videoStreams = null;
|
||||
public AudioStream[] audioStreams = null;
|
||||
public VideoInfoItem nextVideo = null;
|
||||
public Vector<VideoInfoItem> relatedVideos = null;
|
||||
public int videoAvailableStatus = VIDEO_AVAILABLE;
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 26.08.15.
|
||||
@@ -22,13 +24,63 @@ import android.graphics.Bitmap;
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class VideoInfoItem {
|
||||
/**Info object for previews of unopened videos, eg search results, related videos*/
|
||||
public class VideoInfoItem implements Parcelable {
|
||||
public String id = "";
|
||||
public String title = "";
|
||||
public String uploader = "";
|
||||
public String duration = "";
|
||||
public String thumbnail_url = "";
|
||||
public Bitmap thumbnail = null;
|
||||
public String webpage_url = "";
|
||||
public String upload_date = "";
|
||||
public String view_count = "";
|
||||
|
||||
public String duration = "";
|
||||
|
||||
protected VideoInfoItem(Parcel in) {
|
||||
id = in.readString();
|
||||
title = in.readString();
|
||||
uploader = in.readString();
|
||||
duration = in.readString();
|
||||
thumbnail_url = in.readString();
|
||||
thumbnail = (Bitmap) in.readValue(Bitmap.class.getClassLoader());
|
||||
webpage_url = in.readString();
|
||||
upload_date = in.readString();
|
||||
view_count = in.readString();
|
||||
}
|
||||
|
||||
public VideoInfoItem() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(id);
|
||||
dest.writeString(title);
|
||||
dest.writeString(uploader);
|
||||
dest.writeString(duration);
|
||||
dest.writeString(thumbnail_url);
|
||||
dest.writeValue(thumbnail);
|
||||
dest.writeString(webpage_url);
|
||||
dest.writeString(upload_date);
|
||||
dest.writeString(view_count);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static final Parcelable.Creator<VideoInfoItem> CREATOR = new Parcelable.Creator<VideoInfoItem>() {
|
||||
@Override
|
||||
public VideoInfoItem createFromParcel(Parcel in) {
|
||||
return new VideoInfoItem(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoInfoItem[] newArray(int size) {
|
||||
return new VideoInfoItem[size];
|
||||
}
|
||||
};
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 24.10.15.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||
* VideoInfoItemViewCreator.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class VideoInfoItemViewCreator {
|
||||
private static final String TAG = VideoInfoItemViewCreator.class.toString();
|
||||
|
||||
LayoutInflater inflater;
|
||||
|
||||
public VideoInfoItemViewCreator(LayoutInflater inflater) {
|
||||
this.inflater = inflater;
|
||||
}
|
||||
|
||||
public View getViewByVideoInfoItem(View convertView, ViewGroup parent, VideoInfoItem info) {
|
||||
ViewHolder holder;
|
||||
if(convertView == null) {
|
||||
convertView = inflater.inflate(R.layout.video_item, parent, false);
|
||||
holder = new ViewHolder();
|
||||
holder.itemThumbnailView = (ImageView) convertView.findViewById(R.id.itemThumbnailView);
|
||||
holder.itemVideoTitleView = (TextView) convertView.findViewById(R.id.itemVideoTitleView);
|
||||
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
|
||||
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
|
||||
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
if(info.thumbnail == null) {
|
||||
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
||||
} else {
|
||||
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
|
||||
}
|
||||
holder.itemVideoTitleView.setText(info.title);
|
||||
holder.itemUploaderView.setText(info.uploader);
|
||||
holder.itemDurationView.setText(info.duration);
|
||||
if(!info.upload_date.isEmpty()) {
|
||||
holder.itemUploadDateView.setText(info.upload_date);
|
||||
} else {
|
||||
//tweak if necessary: This is a hack to prevent having white space in the layout :P
|
||||
holder.itemUploadDateView.setText(info.view_count);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
public ImageView itemThumbnailView;
|
||||
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView;
|
||||
}
|
||||
|
||||
}
|
@@ -1,22 +1,15 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
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.WindowManager;
|
||||
|
||||
import org.schabi.newpipe.youtube.YoutubeExtractor;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
||||
/**
|
||||
@@ -41,9 +34,10 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = VideoItemDetailActivity.class.toString();
|
||||
|
||||
VideoItemDetailFragment fragment;
|
||||
|
||||
private String videoUrl;
|
||||
private int currentStreamingService = -1;
|
||||
private boolean isLandscape;
|
||||
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -51,7 +45,6 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
|
||||
// Show the Up button in the action bar.
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
ActionBarHandler.getHandler().setupNavMenu(this);
|
||||
|
||||
// savedInstanceState is non-null when there is fragment state
|
||||
// saved from previous configurations of this activity
|
||||
@@ -68,6 +61,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
// this means the video was called though another app
|
||||
if (getIntent().getData() != null) {
|
||||
videoUrl = getIntent().getData().toString();
|
||||
Log.i(TAG, "video URL passed:\"" + videoUrl + "\"");
|
||||
StreamingService[] serviceList = ServiceList.getServices();
|
||||
Extractor extractor = null;
|
||||
for (int i = 0; i < serviceList.length; i++) {
|
||||
@@ -75,14 +69,17 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
|
||||
try {
|
||||
currentStreamingService = i;
|
||||
extractor = (Extractor) ServiceList.getService(i)
|
||||
.getExtractorClass().newInstance();
|
||||
extractor = ServiceList.getService(i).getExtractorInstance();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(extractor == null) {
|
||||
Toast.makeText(this, R.string.urlNotSupportedText, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
arguments.putString(VideoItemDetailFragment.VIDEO_URL,
|
||||
extractor.getVideoUrl(extractor.getVideoId(videoUrl)));
|
||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
||||
@@ -95,14 +92,27 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
|
||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
|
||||
}
|
||||
// Create the detail fragment and add it to the activity
|
||||
// using a fragment transaction.
|
||||
VideoItemDetailFragment fragment = new VideoItemDetailFragment();
|
||||
fragment.setArguments(arguments);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.videoitem_detail_container, fragment)
|
||||
.commit();
|
||||
|
||||
} else {
|
||||
videoUrl = savedInstanceState.getString(VideoItemDetailFragment.VIDEO_URL);
|
||||
currentStreamingService = savedInstanceState.getInt(VideoItemDetailFragment.STREAMING_SERVICE);
|
||||
arguments = savedInstanceState;
|
||||
}
|
||||
|
||||
// Create the detail fragment and add it to the activity
|
||||
// using a fragment transaction.
|
||||
fragment = new VideoItemDetailFragment();
|
||||
fragment.setArguments(arguments);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.videoitem_detail_container, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl);
|
||||
outState.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingService);
|
||||
outState.putBoolean(VideoItemDetailFragment.AUTO_PLAY, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,25 +123,23 @@ public class VideoItemDetailActivity extends AppCompatActivity {
|
||||
// activity, the Up button is shown. Use NavUtils to allow users
|
||||
// to navigate up one level in the application structure. For
|
||||
// more details, see the Navigation pattern on Android Design:
|
||||
//
|
||||
|
||||
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
|
||||
//
|
||||
|
||||
Intent intent = new Intent(this, VideoItemListActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
NavUtils.navigateUpTo(this, intent);
|
||||
return true;
|
||||
} else {
|
||||
ActionBarHandler.getHandler().onItemSelected(item, this);
|
||||
return fragment.onOptionsItemSelected(item) ||
|
||||
super.onOptionsItemSelected(item);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featured, Menu menu) {
|
||||
super.onCreatePanelMenu(featured, menu);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
ActionBarHandler.getHandler().setupMenu(menu, inflater, this);
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
fragment.onCreateOptionsMenu(menu, getMenuInflater());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,23 +2,23 @@ package org.schabi.newpipe;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||
* VideoItemListActivity.java is part of NewPipe.
|
||||
@@ -41,13 +41,25 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
implements VideoItemListFragment.Callbacks {
|
||||
|
||||
private static final String TAG = VideoItemListFragment.class.toString();
|
||||
|
||||
// arguments to give to this activity
|
||||
public static final String VIDEO_INFO_ITEMS = "video_info_items";
|
||||
|
||||
// savedInstanceBundle arguments
|
||||
private static final String QUERY = "query";
|
||||
private static final String STREAMING_SERVICE = "streaming_service";
|
||||
|
||||
// activity modes
|
||||
private static final int SEARCH_MODE = 0;
|
||||
private static final int PRESENT_VIDEOS_MODE = 1;
|
||||
|
||||
private int mode = SEARCH_MODE;
|
||||
private int currentStreamingServiceId = -1;
|
||||
private String searchQuery = "";
|
||||
|
||||
private VideoItemListFragment listFragment;
|
||||
private VideoItemDetailFragment videoFragment = null;
|
||||
Menu menu = null;
|
||||
|
||||
public class SearchVideoQueryListener implements SearchView.OnQueryTextListener {
|
||||
|
||||
@@ -68,7 +80,6 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
// onQueryTextSubmit to trigger twice when focus is not cleared.
|
||||
// See: http://stackoverflow.com/questions/17874951/searchview-onquerytextsubmit-runs-twice-while-i-pressed-once
|
||||
getCurrentFocus().clearFocus();
|
||||
hideWatermark();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -82,13 +93,6 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
|
||||
}
|
||||
|
||||
private void hideWatermark() {
|
||||
ImageView waterMark = (ImageView) findViewById(R.id.list_view_watermark);
|
||||
if(waterMark != null) {
|
||||
waterMark.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
|
||||
* device.
|
||||
@@ -100,21 +104,33 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_videoitem_list);
|
||||
|
||||
listFragment = (VideoItemListFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.videoitem_list);
|
||||
|
||||
//-------- remove this line when multiservice support is implemented ----------
|
||||
//------ todo: remove this line when multiservice support is implemented ------
|
||||
currentStreamingServiceId = ServiceList.getIdOfService("Youtube");
|
||||
//-----------------------------------------------------------------------------
|
||||
VideoItemListFragment listFragment = (VideoItemListFragment) getSupportFragmentManager()
|
||||
|
||||
listFragment = (VideoItemListFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.videoitem_list);
|
||||
listFragment.setStreamingService(ServiceList.getService(currentStreamingServiceId));
|
||||
|
||||
if(savedInstanceState != null) {
|
||||
Bundle arguments = getIntent().getExtras();
|
||||
|
||||
if(arguments != null) {
|
||||
//Parcelable[] p = arguments.getParcelableArray(VIDEO_INFO_ITEMS);
|
||||
ArrayList<VideoInfoItem> p = arguments.getParcelableArrayList(VIDEO_INFO_ITEMS);
|
||||
if(p != null) {
|
||||
mode = PRESENT_VIDEOS_MODE;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
listFragment.present(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(savedInstanceState != null
|
||||
&& mode != PRESENT_VIDEOS_MODE) {
|
||||
searchQuery = savedInstanceState.getString(QUERY);
|
||||
currentStreamingServiceId = savedInstanceState.getInt(STREAMING_SERVICE);
|
||||
if(!searchQuery.isEmpty()) {
|
||||
hideWatermark();
|
||||
listFragment.search(searchQuery);
|
||||
}
|
||||
}
|
||||
@@ -134,19 +150,18 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
.setActivateOnItemClick(true);
|
||||
|
||||
SearchView searchView = (SearchView)findViewById(R.id.searchViewTablet);
|
||||
// Somehow the seticonifiedbydefault property set by the layout xml is not working on
|
||||
// the support version on SearchView, so it needs to be set programmatically.
|
||||
searchView.setIconifiedByDefault(false);
|
||||
searchView.setIconified(false);
|
||||
searchView.setOnQueryTextListener(new SearchVideoQueryListener());
|
||||
|
||||
ActionBarHandler.getHandler().setupNavMenu(this);
|
||||
|
||||
if(mode != PRESENT_VIDEOS_MODE) {
|
||||
// Somehow the seticonifiedbydefault property set by the layout xml is not working on
|
||||
// the support version on SearchView, so it needs to be set programmatically.
|
||||
searchView.setIconifiedByDefault(false);
|
||||
searchView.setIconified(false);
|
||||
searchView.setOnQueryTextListener(new SearchVideoQueryListener());
|
||||
} else {
|
||||
searchView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsActivity.initSettings(this);
|
||||
|
||||
// TODO: If exposing deep links into your app, handle intents here.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,10 +183,17 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
arguments.putString(VideoItemDetailFragment.ARG_ITEM_ID, id);
|
||||
arguments.putString(VideoItemDetailFragment.VIDEO_URL, webpage_url);
|
||||
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingServiceId);
|
||||
VideoItemDetailFragment fragment = new VideoItemDetailFragment();
|
||||
fragment.setArguments(arguments);
|
||||
videoFragment = new VideoItemDetailFragment();
|
||||
videoFragment.setArguments(arguments);
|
||||
videoFragment.setOnInvokeCreateOptionsMenuListener(new VideoItemDetailFragment.OnInvokeCreateOptionsMenuListener() {
|
||||
@Override
|
||||
public void createOptionsMenu() {
|
||||
menu.clear();
|
||||
onCreateOptionsMenu(menu);
|
||||
}
|
||||
});
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.videoitem_detail_container, fragment)
|
||||
.replace(R.id.videoitem_detail_container, videoFragment)
|
||||
.commit();
|
||||
} else {
|
||||
// In single-pane mode, simply start the detail activity
|
||||
@@ -185,10 +207,12 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
|
||||
public boolean onCreatePanelMenu(int featured, Menu menu) {
|
||||
super.onCreatePanelMenu(featured, menu);
|
||||
if(findViewById(R.id.videoitem_detail_container) == null) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
this.menu = menu;
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
if(mode != PRESENT_VIDEOS_MODE &&
|
||||
findViewById(R.id.videoitem_detail_container) == null) {
|
||||
inflater.inflate(R.menu.videoitem_list, menu);
|
||||
MenuItem searchItem = menu.findItem(R.id.action_search);
|
||||
SearchView searchView = (SearchView) searchItem.getActionView();
|
||||
@@ -196,9 +220,10 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
searchView.setOnQueryTextListener(
|
||||
new SearchVideoQueryListener());
|
||||
|
||||
} else if (videoFragment != null){
|
||||
videoFragment.onCreateOptionsMenu(menu, inflater);
|
||||
} else {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
ActionBarHandler.getHandler().setupMenu(menu, inflater, this);
|
||||
inflater.inflate(R.menu.videoitem_two_pannel, menu);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -207,14 +232,23 @@ public class VideoItemListActivity extends AppCompatActivity
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if(id == R.id.action_settings) {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
ActionBarHandler.getHandler().onItemSelected(item, this);
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
||||
switch(id) {
|
||||
case android.R.id.home: {
|
||||
Intent intent = new Intent(this, VideoItemListActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
NavUtils.navigateUpTo(this, intent);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_settings: {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return videoFragment.onOptionsItemSelected(item) ||
|
||||
super.onOptionsItemSelected(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -13,6 +15,7 @@ import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
@@ -42,6 +45,11 @@ public class VideoItemListFragment extends ListFragment {
|
||||
private StreamingService streamingService = null;
|
||||
private VideoListAdapter videoListAdapter;
|
||||
|
||||
// activity modes
|
||||
private static final int SEARCH_MODE = 0;
|
||||
private static final int PRESENT_VIDEOS_MODE = 1;
|
||||
|
||||
private int mode = SEARCH_MODE;
|
||||
private String query = "";
|
||||
private int lastPage = 0;
|
||||
|
||||
@@ -51,29 +59,30 @@ public class VideoItemListFragment extends ListFragment {
|
||||
private LoadThumbsRunnable loadThumbsRunnable = null;
|
||||
// used to track down if results posted by threads ar still valid
|
||||
private int currentRequestId = -1;
|
||||
private ListView list;
|
||||
|
||||
private class ResultRunnable implements Runnable {
|
||||
private SearchEngine.Result result;
|
||||
private int reuqestId;
|
||||
private int requestId;
|
||||
public ResultRunnable(SearchEngine.Result result, int requestId) {
|
||||
this.result = result;
|
||||
this.reuqestId = requestId;
|
||||
this.requestId = requestId;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
updateListOnResult(result, reuqestId);
|
||||
updateListOnResult(result, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchRunnable implements Runnable {
|
||||
private Class engineClass = null;
|
||||
private SearchEngine engine;
|
||||
private String query;
|
||||
private int page;
|
||||
Handler h = new Handler();
|
||||
private volatile boolean run = true;
|
||||
private int requestId;
|
||||
public SearchRunnable(Class engineClass, String query, int page, int requestId) {
|
||||
this.engineClass = engineClass;
|
||||
public SearchRunnable(SearchEngine engine, String query, int page, int requestId) {
|
||||
this.engine = engine;
|
||||
this.query = query;
|
||||
this.page = page;
|
||||
this.requestId = requestId;
|
||||
@@ -83,15 +92,12 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
SearchEngine engine = null;
|
||||
try {
|
||||
engine = (SearchEngine) engineClass.newInstance();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SearchEngine.Result result = engine.search(query, page);
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String searchLanguageKey = getContext().getString(R.string.searchLanguage);
|
||||
String searchLanguage = sp.getString(searchLanguageKey, "en");
|
||||
SearchEngine.Result result = engine.search(query, page, searchLanguage);
|
||||
Log.i(TAG, "language code passed:\""+searchLanguage+"\"");
|
||||
if(run) {
|
||||
h.post(new ResultRunnable(result, requestId));
|
||||
}
|
||||
@@ -162,7 +168,16 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
}
|
||||
|
||||
public void present(List<VideoInfoItem> videoList) {
|
||||
mode = PRESENT_VIDEOS_MODE;
|
||||
setListShown(true);
|
||||
getListView().smoothScrollToPosition(0);
|
||||
|
||||
updateList(videoList);
|
||||
}
|
||||
|
||||
public void search(String query) {
|
||||
mode = SEARCH_MODE;
|
||||
this.query = query;
|
||||
this.lastPage = 1;
|
||||
videoListAdapter.clearVideoList();
|
||||
@@ -180,7 +195,8 @@ public class VideoItemListFragment extends ListFragment {
|
||||
private void startSearch(String query, int page) {
|
||||
currentRequestId++;
|
||||
terminateThreads();
|
||||
searchRunnable = new SearchRunnable(streamingService.getSearchEngineClass(), query, page, currentRequestId);
|
||||
searchRunnable = new SearchRunnable(streamingService.getSearchEngineInstance(),
|
||||
query, page, currentRequestId);
|
||||
searchThread = new Thread(searchRunnable);
|
||||
searchThread.start();
|
||||
}
|
||||
@@ -204,7 +220,7 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateList(Vector<VideoInfoItem> list) {
|
||||
private void updateList(List<VideoInfoItem> list) {
|
||||
try {
|
||||
videoListAdapter.addVideoList(list);
|
||||
terminateThreads();
|
||||
@@ -213,7 +229,7 @@ public class VideoItemListFragment extends ListFragment {
|
||||
loadThumbsThread = new Thread(loadThumbsRunnable);
|
||||
loadThumbsThread.start();
|
||||
} catch(java.lang.IllegalStateException e) {
|
||||
Log.w(TAG, "Trying to set value while activity is not existing anymore.");
|
||||
Log.w(TAG, "Trying to set value while activity doesn't exist anymore.");
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -230,15 +246,11 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
if(searchThread != null) {
|
||||
searchRunnable.terminate();
|
||||
// No need to join, since we don't realy terminate the thread. We just demand
|
||||
// No need to join, since we don't really terminate the thread. We just demand
|
||||
// it to post its result runnable into the gui main loop.
|
||||
}
|
||||
}
|
||||
|
||||
void displayList() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The serialization (saved instance state) Bundle key representing the
|
||||
* activated item position. Only used on tablets.
|
||||
@@ -272,6 +284,7 @@ public class VideoItemListFragment extends ListFragment {
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
list = getListView();
|
||||
videoListAdapter = new VideoListAdapter(getActivity(), this);
|
||||
setListAdapter(videoListAdapter);
|
||||
|
||||
@@ -283,8 +296,6 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
|
||||
getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||
private static final float OVERSCROLL_THRESHOLD_IN_PIXELS = 100;
|
||||
private float downY;
|
||||
long lastScrollDate = 0;
|
||||
|
||||
@Override
|
||||
@@ -293,8 +304,8 @@ public class VideoItemListFragment extends ListFragment {
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||
ListView list = getListView();
|
||||
if (list.getChildAt(0) != null
|
||||
if (mode != PRESENT_VIDEOS_MODE
|
||||
&& list.getChildAt(0) != null
|
||||
&& list.getLastVisiblePosition() == list.getAdapter().getCount() - 1
|
||||
&& list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) {
|
||||
long time = System.currentTimeMillis();
|
||||
@@ -309,15 +320,15 @@ public class VideoItemListFragment extends ListFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
// Activities containing this fragment must implement its callbacks.
|
||||
if (!(activity instanceof Callbacks)) {
|
||||
if (!(context instanceof Callbacks)) {
|
||||
throw new IllegalStateException("Activity must implement fragment's callbacks.");
|
||||
}
|
||||
|
||||
mCallbacks = (Callbacks) activity;
|
||||
mCallbacks = (Callbacks) context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -2,18 +2,18 @@ package org.schabi.newpipe;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Created by the-scrabi on 11.08.15.
|
||||
* Created by Christian Schabesberger on 11.08.15.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||
* VideoListAdapter.java is part of NewPipe.
|
||||
@@ -33,21 +33,23 @@ import java.util.Vector;
|
||||
*/
|
||||
|
||||
public class VideoListAdapter extends BaseAdapter {
|
||||
|
||||
private static final String TAG = VideoListAdapter.class.toString();
|
||||
private LayoutInflater inflater;
|
||||
|
||||
private Context context;
|
||||
private VideoInfoItemViewCreator viewCreator;
|
||||
private Vector<VideoInfoItem> videoList = new Vector<>();
|
||||
private Vector<Boolean> downloadedThumbnailList = new Vector<>();
|
||||
VideoItemListFragment videoListFragment;
|
||||
ListView listView;
|
||||
|
||||
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(context));
|
||||
this.videoListFragment = videoListFragment;
|
||||
this.listView = videoListFragment.getListView();
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void addVideoList(Vector<VideoInfoItem> videos) {
|
||||
public void addVideoList(List<VideoInfoItem> videos) {
|
||||
videoList.addAll(videos);
|
||||
for(int i = 0; i < videos.size(); i++) {
|
||||
downloadedThumbnailList.add(false);
|
||||
@@ -96,42 +98,14 @@ public class VideoListAdapter extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ViewHolder holder;
|
||||
if(convertView == null) {
|
||||
convertView = inflater.inflate(R.layout.video_item, parent, false);
|
||||
holder = new ViewHolder();
|
||||
holder.itemThumbnailView = (ImageView) convertView.findViewById(R.id.itemThumbnailView);
|
||||
holder.itemVideoTitleView = (TextView) convertView.findViewById(R.id.itemVideoTitleView);
|
||||
holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView);
|
||||
holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView);
|
||||
holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
final Context context = parent.getContext();
|
||||
if(videoList.get(position).thumbnail == null) {
|
||||
holder.itemThumbnailView.setImageResource(R.drawable.dummi_thumbnail);
|
||||
} else {
|
||||
holder.itemThumbnailView.setImageBitmap(videoList.get(position).thumbnail);
|
||||
}
|
||||
holder.itemVideoTitleView.setText(videoList.get(position).title);
|
||||
holder.itemUploaderView.setText(videoList.get(position).uploader);
|
||||
holder.itemDurationView.setText(videoList.get(position).duration);
|
||||
holder.itemUploadDateView.setText(videoList.get(position).upload_date);
|
||||
convertView = viewCreator.getViewByVideoInfoItem(convertView, parent, videoList.get(position));
|
||||
|
||||
if(listView.isItemChecked(position)) {
|
||||
convertView.setBackgroundColor(context.getResources().getColor(R.color.primaryColorYoutube));
|
||||
convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube));
|
||||
} else {
|
||||
convertView.setBackgroundColor(0);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
public ImageView itemThumbnailView;
|
||||
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView;
|
||||
}
|
||||
}
|
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