Compare commits
108 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 |
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 +0,0 @@
|
||||
NewPipe
|
||||
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
@@ -1,3 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
||||
3
.idea/dictionaries/the_scrabi.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="the-scrabi" />
|
||||
</component>
|
||||
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1 +1,3 @@
|
||||
.gitignore
|
||||
/build
|
||||
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
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
@@ -19,8 +16,6 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 18.08.15.
|
||||
*
|
||||
@@ -45,10 +40,7 @@ public class ActionBarHandler {
|
||||
private static final String TAG = ActionBarHandler.class.toString();
|
||||
private static final String KORE_PACKET = "org.xbmc.kore";
|
||||
|
||||
private static ActionBarHandler handler = null;
|
||||
|
||||
private Context context = null;
|
||||
private String webisteUrl = "";
|
||||
private String websiteUrl = "";
|
||||
private AppCompatActivity activity;
|
||||
private VideoInfo.VideoStream[] videoStreams = null;
|
||||
private VideoInfo.AudioStream audioStream = null;
|
||||
@@ -57,14 +49,7 @@ public class ActionBarHandler {
|
||||
|
||||
SharedPreferences defaultPreferences = null;
|
||||
|
||||
public static ActionBarHandler getHandler() {
|
||||
if(handler == null) {
|
||||
handler = new ActionBarHandler();
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
class ForamatItemSelectListener implements ActionBar.OnNavigationListener {
|
||||
class FormatItemSelectListener implements ActionBar.OnNavigationListener {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||
selectFormatItem((int)itemId);
|
||||
@@ -72,6 +57,10 @@ public class ActionBarHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public ActionBarHandler(AppCompatActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void setupNavMenu(AppCompatActivity activity) {
|
||||
this.activity = activity;
|
||||
activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
||||
@@ -80,14 +69,15 @@ public class ActionBarHandler {
|
||||
public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) {
|
||||
this.videoStreams = videoStreams;
|
||||
selectedStream = 0;
|
||||
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
String[] itemArray = new String[videoStreams.length];
|
||||
String defaultResolution = defaultPreferences
|
||||
.getString(context.getString(R.string.defaultResolutionPreference),
|
||||
context.getString(R.string.defaultResolutionListItem));
|
||||
.getString(activity.getString(R.string.defaultResolutionPreference),
|
||||
activity.getString(R.string.defaultResolutionListItem));
|
||||
int defaultResolutionPos = 0;
|
||||
|
||||
for(int i = 0; i < videoStreams.length; i++) {
|
||||
itemArray[i] = VideoInfo.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
|
||||
itemArray[i] = MediaFormat.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
|
||||
if(defaultResolution.equals(videoStreams[i].resolution)) {
|
||||
defaultResolutionPos = i;
|
||||
}
|
||||
@@ -98,27 +88,25 @@ public class ActionBarHandler {
|
||||
if(activity != null) {
|
||||
ActionBar ab = activity.getSupportActionBar();
|
||||
ab.setListNavigationCallbacks(itemAdapter
|
||||
,new ForamatItemSelectListener());
|
||||
,new FormatItemSelectListener());
|
||||
ab.setSelectedNavigationItem(defaultResolutionPos);
|
||||
}
|
||||
|
||||
// set audioStream
|
||||
audioStream = null;
|
||||
String preferedFormat = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getString(context.getString(R.string.defaultAudioFormatPreference), "webm");
|
||||
String preferedFormat = defaultPreferences
|
||||
.getString(activity.getString(R.string.defaultAudioFormatPreference), "webm");
|
||||
if(preferedFormat.equals("webm")) {
|
||||
for(VideoInfo.AudioStream s : audioStreams) {
|
||||
if(s.format == VideoInfo.I_WEBMA) {
|
||||
if(s.format == MediaFormat.WEBMA.id) {
|
||||
audioStream = s;
|
||||
}
|
||||
}
|
||||
} else if(preferedFormat.equals("m4a")){
|
||||
for(VideoInfo.AudioStream s : audioStreams) {
|
||||
Log.d(TAG, VideoInfo.getMimeById(s.format) + " : " + Integer.toString(s.bandWidth));
|
||||
if(s.format == VideoInfo.I_M4A &&
|
||||
(audioStream == null || audioStream.bandWidth > s.bandWidth)) {
|
||||
if(s.format == MediaFormat.M4A.id &&
|
||||
(audioStream == null || audioStream.bandwidth > s.bandwidth)) {
|
||||
audioStream = s;
|
||||
Log.d(TAG, "last choosen");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,79 +116,67 @@ public class ActionBarHandler {
|
||||
selectedStream = i;
|
||||
}
|
||||
|
||||
public boolean setupMenu(Menu menu, MenuInflater inflater, Context context) {
|
||||
this.context = context;
|
||||
public boolean setupMenu(Menu menu, MenuInflater inflater) {
|
||||
// CAUTION set item properties programmatically otherwise it would not be accepted by
|
||||
// appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
|
||||
|
||||
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
inflater.inflate(R.menu.videoitem_detail, menu);
|
||||
MenuItem playItem = menu.findItem(R.id.menu_item_play);
|
||||
MenuItem shareItem = menu.findItem(R.id.menu_item_share);
|
||||
MenuItem castItem = menu.findItem(R.id.action_play_with_kodi);
|
||||
|
||||
MenuItemCompat.setShowAsAction(playItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
|
||||
| MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
MenuItemCompat.setShowAsAction(shareItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
|
||||
| MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
|
||||
castItem.setVisible(defaultPreferences
|
||||
.getBoolean(context.getString(R.string.showPlayWidthKodiPreference), false));
|
||||
.getBoolean(activity.getString(R.string.showPlayWidthKodiPreference), false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onItemSelected(MenuItem item, Context context) {
|
||||
this.context = context;
|
||||
public boolean onItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch(id) {
|
||||
case R.id.menu_item_play:
|
||||
playVideo();
|
||||
break;
|
||||
case R.id.menu_item_share:
|
||||
if(!videoTitle.isEmpty()) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, webisteUrl);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, websiteUrl);
|
||||
intent.setType("text/plain");
|
||||
context.startActivity(Intent.createChooser(intent, context.getString(R.string.shareDialogTitle)));
|
||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.shareDialogTitle)));
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case R.id.menu_item_openInBrowser: {
|
||||
openInBrowser();
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case R.id.menu_item_download:
|
||||
downloadVideo();
|
||||
break;
|
||||
return true;
|
||||
case R.id.action_settings: {
|
||||
Intent intent = new Intent(context, SettingsActivity.class);
|
||||
context.startActivity(intent);
|
||||
Intent intent = new Intent(activity, SettingsActivity.class);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
break;
|
||||
case R.id.action_play_with_kodi:
|
||||
playWithKodi();
|
||||
break;
|
||||
return true;
|
||||
case R.id.menu_item_play_audio:
|
||||
playAudio();
|
||||
break;
|
||||
return true;
|
||||
default:
|
||||
Log.e(TAG, "Menu Item not known");
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setVideoInfo(String websiteUrl, String videoTitle) {
|
||||
this.webisteUrl = websiteUrl;
|
||||
this.websiteUrl = websiteUrl;
|
||||
this.videoTitle = videoTitle;
|
||||
}
|
||||
|
||||
public void playVideo() {
|
||||
// ----------- THE MAGIC MOMENT ---------------
|
||||
if(!videoTitle.isEmpty()) {
|
||||
if (PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getBoolean(context.getString(R.string.useExternalPlayer), false)) {
|
||||
if (PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.getBoolean(activity.getString(R.string.useExternalPlayer), false)) {
|
||||
|
||||
// External Player
|
||||
Intent intent = new Intent();
|
||||
@@ -208,22 +184,22 @@ public class ActionBarHandler {
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
|
||||
intent.setDataAndType(Uri.parse(videoStreams[selectedStream].url),
|
||||
VideoInfo.getMimeById(videoStreams[selectedStream].format));
|
||||
MediaFormat.getMimeById(videoStreams[selectedStream].format));
|
||||
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
|
||||
intent.putExtra("title", videoTitle);
|
||||
|
||||
context.startActivity(intent); // HERE !!!
|
||||
activity.startActivity(intent); // HERE !!!
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(R.string.noPlayerFound)
|
||||
.setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(context.getString(R.string.fdroidVLCurl)));
|
||||
context.startActivity(intent);
|
||||
intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl)));
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@@ -236,21 +212,20 @@ public class ActionBarHandler {
|
||||
}
|
||||
} else {
|
||||
// Internal Player
|
||||
Intent intent = new Intent(context, PlayVideoActivity.class);
|
||||
Intent intent = new Intent(activity, PlayVideoActivity.class);
|
||||
intent.putExtra(PlayVideoActivity.VIDEO_TITLE, videoTitle);
|
||||
intent.putExtra(PlayVideoActivity.STREAM_URL, videoStreams[selectedStream].url);
|
||||
intent.putExtra(PlayVideoActivity.VIDEO_URL, webisteUrl);
|
||||
context.startActivity(intent);
|
||||
intent.putExtra(PlayVideoActivity.VIDEO_URL, websiteUrl);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
// --------------------------------------------
|
||||
}
|
||||
|
||||
public void downloadVideo() {
|
||||
Log.d(TAG, "bla");
|
||||
if(!videoTitle.isEmpty()) {
|
||||
String videoSuffix = "." + VideoInfo.getSuffixById(videoStreams[selectedStream].format);
|
||||
String audioSuffix = "." + VideoInfo.getSuffixById(audioStream.format);
|
||||
String videoSuffix = "." + MediaFormat.getSuffixById(videoStreams[selectedStream].format);
|
||||
String audioSuffix = "." + MediaFormat.getSuffixById(audioStream.format);
|
||||
Bundle args = new Bundle();
|
||||
args.putString(DownloadDialog.FILE_SUFFIX_VIDEO, videoSuffix);
|
||||
args.putString(DownloadDialog.FILE_SUFFIX_AUDIO, audioSuffix);
|
||||
@@ -267,9 +242,9 @@ public class ActionBarHandler {
|
||||
if(!videoTitle.isEmpty()) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(webisteUrl));
|
||||
intent.setData(Uri.parse(websiteUrl));
|
||||
|
||||
context.startActivity(Intent.createChooser(intent, context.getString(R.string.chooseBrowser)));
|
||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.chooseBrowser)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,19 +253,19 @@ public class ActionBarHandler {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setPackage(KORE_PACKET);
|
||||
intent.setData(Uri.parse(webisteUrl.replace("https", "http")));
|
||||
context.startActivity(intent);
|
||||
intent.setData(Uri.parse(websiteUrl.replace("https", "http")));
|
||||
activity.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(R.string.koreNotFound)
|
||||
.setPositiveButton(R.string.installeKore, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(context.getString(R.string.fdroidKoreUrl)));
|
||||
context.startActivity(intent);
|
||||
intent.setData(Uri.parse(activity.getString(R.string.fdroidKoreUrl)));
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@@ -309,21 +284,21 @@ public class ActionBarHandler {
|
||||
try {
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(Uri.parse(audioStream.url),
|
||||
VideoInfo.getMimeById(audioStream.format));
|
||||
MediaFormat.getMimeById(audioStream.format));
|
||||
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
|
||||
intent.putExtra("title", videoTitle);
|
||||
context.startActivity(intent); // HERE !!!
|
||||
activity.startActivity(intent); // HERE !!!
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(R.string.noPlayerFound)
|
||||
.setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(context.getString(R.string.fdroidVLCurl)));
|
||||
context.startActivity(intent);
|
||||
intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl)));
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@@ -333,6 +308,8 @@ public class ActionBarHandler {
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 "";
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ 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;
|
||||
@@ -19,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;
|
||||
|
||||
/**
|
||||
@@ -84,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);
|
||||
@@ -138,9 +133,11 @@ 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) {
|
||||
@@ -203,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,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() {
|
||||
@@ -250,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);
|
||||
@@ -274,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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,40 @@
|
||||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.Image;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
@@ -60,21 +69,32 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
public static final String STREAMING_SERVICE = "streaming_service";
|
||||
public static final String AUTO_PLAY = "auto_play";
|
||||
|
||||
private AppCompatActivity activity;
|
||||
private ActionBarHandler actionBarHandler;
|
||||
|
||||
private boolean autoPlayEnabled = false;
|
||||
private Thread extractorThread = null;
|
||||
private VideoInfo currentVideoInfo = null;
|
||||
private boolean showNextVideoItem = false;
|
||||
|
||||
public interface OnInvokeCreateOptionsMenuListener {
|
||||
void createOptionsMenu();
|
||||
}
|
||||
|
||||
private OnInvokeCreateOptionsMenuListener onInvokeCreateOptionsMenuListener = null;
|
||||
|
||||
private class ExtractorRunnable implements Runnable {
|
||||
private Handler h = new Handler();
|
||||
private Class extractorClass;
|
||||
private Extractor extractor;
|
||||
private String videoUrl;
|
||||
public ExtractorRunnable(String videoUrl, Class extractorClass, VideoItemDetailFragment f) {
|
||||
this.extractorClass = extractorClass;
|
||||
|
||||
public ExtractorRunnable(String videoUrl, Extractor extractor, VideoItemDetailFragment f) {
|
||||
this.extractor = extractor;
|
||||
this.videoUrl = videoUrl;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Extractor extractor = (Extractor) extractorClass.newInstance();
|
||||
VideoInfo videoInfo = extractor.getVideoInfo(videoUrl);
|
||||
h.post(new VideoResultReturnedRunnable(videoInfo));
|
||||
if (videoInfo.videoAvailableStatus == VideoInfo.VIDEO_AVAILABLE) {
|
||||
@@ -82,12 +102,22 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
BitmapFactory.decodeStream(
|
||||
new URL(videoInfo.thumbnail_url)
|
||||
.openConnection()
|
||||
.getInputStream()), SetThumbnailRunnable.VIDEO_THUMBNAIL));
|
||||
.getInputStream()),
|
||||
SetThumbnailRunnable.VIDEO_THUMBNAIL));
|
||||
h.post(new SetThumbnailRunnable(
|
||||
BitmapFactory.decodeStream(
|
||||
new URL(videoInfo.uploader_thumbnail_url)
|
||||
.openConnection()
|
||||
.getInputStream()), SetThumbnailRunnable.CHANNEL_THUMBNAIL));
|
||||
.getInputStream()),
|
||||
SetThumbnailRunnable.CHANNEL_THUMBNAIL));
|
||||
if(showNextVideoItem) {
|
||||
h.post(new SetThumbnailRunnable(
|
||||
BitmapFactory.decodeStream(
|
||||
new URL(videoInfo.nextVideo.thumbnail_url)
|
||||
.openConnection()
|
||||
.getInputStream()),
|
||||
SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -103,13 +133,16 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
//todo: fix expired thread error:
|
||||
// If the thread calling this runnable is expired, the following function will crash.
|
||||
updateInfo(videoInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private class SetThumbnailRunnable implements Runnable {
|
||||
public static final int CHANNEL_THUMBNAIL = 2;
|
||||
public static final int VIDEO_THUMBNAIL = 1;
|
||||
public static final int CHANNEL_THUMBNAIL = 2;
|
||||
public static final int NEXT_VIDEO_THUMBNAIL = 3;
|
||||
private Bitmap thumbnail;
|
||||
private int thumbnailId;
|
||||
public SetThumbnailRunnable(Bitmap thumbnail, int id) {
|
||||
@@ -128,72 +161,96 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
try {
|
||||
switch (id) {
|
||||
case SetThumbnailRunnable.VIDEO_THUMBNAIL:
|
||||
|
||||
thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView);
|
||||
break;
|
||||
case SetThumbnailRunnable.CHANNEL_THUMBNAIL:
|
||||
thumbnailView = (ImageView) a.findViewById(R.id.detailUploaderThumbnailView);
|
||||
break;
|
||||
case SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL:
|
||||
FrameLayout nextVideoFrame = (FrameLayout) a.findViewById(R.id.detailNextVideoFrame);
|
||||
thumbnailView = (ImageView) nextVideoFrame.findViewById(R.id.itemThumbnailView);
|
||||
currentVideoInfo.nextVideo.thumbnail = thumbnail;
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Error: Thumbnail id not known");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thumbnailView != null) {
|
||||
thumbnailView.setImageBitmap(thumbnail);
|
||||
}
|
||||
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
// No god programm design i know. :/
|
||||
// Not good program design, I know. :/
|
||||
Log.w(TAG, "updateThumbnail(): Fragment closed before thread ended work");
|
||||
}
|
||||
}
|
||||
|
||||
public void updateInfo(VideoInfo info) {
|
||||
Activity a = getActivity();
|
||||
currentVideoInfo = info;
|
||||
try {
|
||||
ProgressBar progressBar = (ProgressBar) a.findViewById(R.id.detailProgressBar);
|
||||
TextView videoTitleView = (TextView) a.findViewById(R.id.detailVideoTitleView);
|
||||
TextView uploaderView = (TextView) a.findViewById(R.id.detailUploaderView);
|
||||
TextView viewCountView = (TextView) a.findViewById(R.id.detailViewCountView);
|
||||
TextView thumbsUpView = (TextView) a.findViewById(R.id.detailThumbsUpCountView);
|
||||
TextView thumbsDownView = (TextView) a.findViewById(R.id.detailThumbsDownCountView);
|
||||
TextView uploadDateView = (TextView) a.findViewById(R.id.detailUploadDateView);
|
||||
TextView descriptionView = (TextView) a.findViewById(R.id.detailDescriptionView);
|
||||
ImageView thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView);
|
||||
ImageView uploaderThumbnailView = (ImageView) a.findViewById(R.id.detailUploaderThumbnailView);
|
||||
ImageView thumbsUpPic = (ImageView) a.findViewById(R.id.detailThumbsUpImgView);
|
||||
ImageView thumbsDownPic = (ImageView) a.findViewById(R.id.detailThumbsDownImgView);
|
||||
View textSeperationLine = a.findViewById(R.id.textSeperationLine);
|
||||
VideoInfoItemViewCreator videoItemViewCreator =
|
||||
new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()));
|
||||
|
||||
ScrollView contentMainView = (ScrollView) activity.findViewById(R.id.detailMainContent);
|
||||
ProgressBar progressBar = (ProgressBar) activity.findViewById(R.id.detailProgressBar);
|
||||
TextView videoTitleView = (TextView) activity.findViewById(R.id.detailVideoTitleView);
|
||||
TextView uploaderView = (TextView) activity.findViewById(R.id.detailUploaderView);
|
||||
TextView viewCountView = (TextView) activity.findViewById(R.id.detailViewCountView);
|
||||
TextView thumbsUpView = (TextView) activity.findViewById(R.id.detailThumbsUpCountView);
|
||||
TextView thumbsDownView = (TextView) activity.findViewById(R.id.detailThumbsDownCountView);
|
||||
TextView uploadDateView = (TextView) activity.findViewById(R.id.detailUploadDateView);
|
||||
TextView descriptionView = (TextView) activity.findViewById(R.id.detailDescriptionView);
|
||||
ImageView thumbnailView = (ImageView) activity.findViewById(R.id.detailThumbnailView);
|
||||
FrameLayout nextVideoFrame = (FrameLayout) activity.findViewById(R.id.detailNextVideoFrame);
|
||||
RelativeLayout nextVideoRootFrame =
|
||||
(RelativeLayout) activity.findViewById(R.id.detailNextVideoRootLayout);
|
||||
View nextVideoView = videoItemViewCreator
|
||||
.getViewByVideoInfoItem(null, nextVideoFrame, info.nextVideo);
|
||||
nextVideoFrame.addView(nextVideoView);
|
||||
Button nextVideoButton = (Button) activity.findViewById(R.id.detailNextVideoButton);
|
||||
Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton);
|
||||
|
||||
if(textSeperationLine != null) {
|
||||
textSeperationLine.setVisibility(View.VISIBLE);
|
||||
}
|
||||
contentMainView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
videoTitleView.setVisibility(View.VISIBLE);
|
||||
uploaderView.setVisibility(View.VISIBLE);
|
||||
uploadDateView.setVisibility(View.VISIBLE);
|
||||
viewCountView.setVisibility(View.VISIBLE);
|
||||
thumbsUpView.setVisibility(View.VISIBLE);
|
||||
thumbsDownView.setVisibility(View.VISIBLE);
|
||||
uploadDateView.setVisibility(View.VISIBLE);
|
||||
descriptionView.setVisibility(View.VISIBLE);
|
||||
thumbnailView.setVisibility(View.VISIBLE);
|
||||
uploaderThumbnailView.setVisibility(View.VISIBLE);
|
||||
thumbsUpPic.setVisibility(View.VISIBLE);
|
||||
thumbsDownPic.setVisibility(View.VISIBLE);
|
||||
if(!showNextVideoItem) {
|
||||
nextVideoRootFrame.setVisibility(View.GONE);
|
||||
similarVideosButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
switch (info.videoAvailableStatus) {
|
||||
case VideoInfo.VIDEO_AVAILABLE: {
|
||||
videoTitleView.setText(info.title);
|
||||
uploaderView.setText(info.uploader);
|
||||
viewCountView.setText(info.view_count + " " + a.getString(R.string.viewSufix));
|
||||
thumbsUpView.setText(info.like_count);
|
||||
thumbsDownView.setText(info.dislike_count);
|
||||
uploadDateView.setText(a.getString(R.string.uploadDatePrefix) + " " + info.upload_date);
|
||||
|
||||
Locale locale = getPreferredLocale();
|
||||
NumberFormat nf = NumberFormat.getInstance(locale);
|
||||
String localisedViewCount = nf.format(info.view_count);
|
||||
viewCountView.setText(localisedViewCount
|
||||
+ " " + activity.getString(R.string.viewSufix));
|
||||
|
||||
|
||||
thumbsUpView.setText(nf.format(info.like_count));
|
||||
thumbsDownView.setText(nf.format(info.dislike_count));
|
||||
|
||||
//this is horribly convoluted
|
||||
//TODO: find a better way to convert YYYY-MM-DD to a locale-specific date
|
||||
//suggestions welcome
|
||||
int year = Integer.parseInt(info.upload_date.substring(0, 4));
|
||||
int month = Integer.parseInt(info.upload_date.substring(5, 7));
|
||||
int date = Integer.parseInt(info.upload_date.substring(8, 10));
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(year, month, date);
|
||||
Date datum = cal.getTime();
|
||||
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
|
||||
|
||||
String localisedDate = df.format(datum);
|
||||
uploadDateView.setText(
|
||||
activity.getString(R.string.uploadDatePrefix) + " " + localisedDate);
|
||||
descriptionView.setText(Html.fromHtml(info.description));
|
||||
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
ActionBarHandler.getHandler().setVideoInfo(info.webpage_url, info.title);
|
||||
actionBarHandler.setVideoInfo(info.webpage_url, info.title);
|
||||
|
||||
// parse streams
|
||||
Vector<VideoInfo.VideoStream> streamsToUse = new Vector<>();
|
||||
@@ -206,21 +263,38 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
for (int i = 0; i < streamList.length; i++) {
|
||||
streamList[i] = streamsToUse.get(i);
|
||||
}
|
||||
ActionBarHandler.getHandler().setStreams(streamList, info.audioStreams);
|
||||
actionBarHandler.setStreams(streamList, info.audioStreams);
|
||||
}
|
||||
|
||||
nextVideoButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent detailIntent =
|
||||
new Intent(getActivity(), VideoItemDetailActivity.class);
|
||||
detailIntent.putExtra(
|
||||
VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id);
|
||||
detailIntent.putExtra(
|
||||
VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url);
|
||||
//todo: make id dynamic the following line is crap
|
||||
detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, 0);
|
||||
startActivity(detailIntent);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case VideoInfo.VIDEO_UNAVAILABLE_GEMA:
|
||||
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.gruese_die_gema_unangebracht));
|
||||
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(
|
||||
getResources(), R.drawable.gruese_die_gema_unangebracht));
|
||||
break;
|
||||
case VideoInfo.VIDEO_UNAVAILABLE:
|
||||
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.not_available_monkey));
|
||||
thumbnailView.setImageBitmap(BitmapFactory.decodeResource(
|
||||
getResources(), R.drawable.not_available_monkey));
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Video Availeble Status not known.");
|
||||
Log.e(TAG, "Video Available Status not known.");
|
||||
}
|
||||
|
||||
if(autoPlayEnabled) {
|
||||
ActionBarHandler.getHandler().playVideo();
|
||||
actionBarHandler.playVideo();
|
||||
}
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Log.w(TAG, "updateInfo(): Fragment closed before thread ended work... or else");
|
||||
@@ -247,48 +321,94 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
try {
|
||||
StreamingService streamingService = ServiceList.getService(
|
||||
getArguments().getInt(STREAMING_SERVICE));
|
||||
extractorThread = new Thread(new ExtractorRunnable(
|
||||
getArguments().getString(VIDEO_URL), streamingService.getExtractorClass(), this));
|
||||
autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY);
|
||||
extractorThread.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
activity = (AppCompatActivity) getActivity();
|
||||
showNextVideoItem = PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.getBoolean(activity.getString(R.string.showNextVideo), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_videoitem_detail, container, false);
|
||||
actionBarHandler = new ActionBarHandler(activity);
|
||||
actionBarHandler.setupNavMenu(activity);
|
||||
if(onInvokeCreateOptionsMenuListener != null) {
|
||||
onInvokeCreateOptionsMenuListener.createOptionsMenu();
|
||||
}
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceBundle) {
|
||||
super.onActivityCreated(savedInstanceBundle);
|
||||
FloatingActionButton playVideoButton = (FloatingActionButton) getActivity().findViewById(R.id.playVideoButton);
|
||||
FloatingActionButton playVideoButton =
|
||||
(FloatingActionButton) getActivity().findViewById(R.id.playVideoButton);
|
||||
|
||||
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.getBoolean(getString(R.string.leftHandLayout), false) && checkIfLandscape()) {
|
||||
RelativeLayout.LayoutParams oldLayout = (RelativeLayout.LayoutParams) playVideoButton.getLayoutParams();
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams.setMargins(oldLayout.leftMargin, oldLayout.topMargin, oldLayout.rightMargin, oldLayout.rightMargin);
|
||||
playVideoButton.setLayoutParams(layoutParams);
|
||||
}
|
||||
// Sometimes when this fragment is not visible it still gets initiated
|
||||
// then we must not try to access objects of this fragment.
|
||||
// Otherwise the applications would crash.
|
||||
if(playVideoButton != null) {
|
||||
try {
|
||||
StreamingService streamingService = ServiceList.getService(
|
||||
getArguments().getInt(STREAMING_SERVICE));
|
||||
extractorThread = new Thread(new ExtractorRunnable(
|
||||
getArguments().getString(VIDEO_URL), streamingService.getExtractorInstance(), this));
|
||||
|
||||
playVideoButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ActionBarHandler.getHandler().playVideo();
|
||||
autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY);
|
||||
extractorThread.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
if (PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.getBoolean(getString(R.string.leftHandLayout), false) && checkIfLandscape()) {
|
||||
RelativeLayout.LayoutParams oldLayout =
|
||||
(RelativeLayout.LayoutParams) playVideoButton.getLayoutParams();
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams.setMargins(oldLayout.leftMargin, oldLayout.topMargin,
|
||||
oldLayout.rightMargin, oldLayout.bottomMargin);
|
||||
playVideoButton.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
playVideoButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
actionBarHandler.playVideo();
|
||||
}
|
||||
});
|
||||
|
||||
Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton);
|
||||
similarVideosButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(activity, VideoItemListActivity.class);
|
||||
intent.putExtra(VideoItemListActivity.VIDEO_INFO_ITEMS, currentVideoInfo.relatedVideos);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Locale getPreferredLocale() {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String languageKey = getContext().getString(R.string.searchLanguage);
|
||||
String languageCode = "en";//i know the following lines defaults languageCode to "en", but java is picky about uninitialised values
|
||||
languageCode = sp.getString(languageKey, "en");
|
||||
|
||||
if(languageCode.length() == 2) {
|
||||
return new Locale(languageCode);
|
||||
}
|
||||
else if(languageCode.contains("_")) {
|
||||
String country = languageCode
|
||||
.substring(languageCode.indexOf("_"), languageCode.length());
|
||||
return new Locale(languageCode.substring(0, 2), country);
|
||||
}
|
||||
return Locale.getDefault();
|
||||
}
|
||||
|
||||
public boolean checkIfLandscape() {
|
||||
@@ -296,4 +416,18 @@ public class VideoItemDetailFragment extends Fragment {
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
return displayMetrics.heightPixels < displayMetrics.widthPixels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
actionBarHandler.setupMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return actionBarHandler.onItemSelected(item);
|
||||
}
|
||||
|
||||
public void setOnInvokeCreateOptionsMenuListener(OnInvokeCreateOptionsMenuListener listener) {
|
||||
this.onInvokeCreateOptionsMenuListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -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,18 +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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,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
|
||||
@@ -184,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();
|
||||
@@ -195,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;
|
||||
@@ -206,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;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
package org.schabi.newpipe.youtube;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.Extractor;
|
||||
import org.schabi.newpipe.VideoInfo;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.parser.Parser;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.Extractor;
|
||||
import org.schabi.newpipe.MediaFormat;
|
||||
import org.schabi.newpipe.VideoInfo;
|
||||
import org.schabi.newpipe.VideoInfoItem;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 06.08.15.
|
||||
*
|
||||
@@ -48,27 +49,25 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class YoutubeExtractor implements Extractor {
|
||||
|
||||
|
||||
|
||||
private static final String TAG = YoutubeExtractor.class.toString();
|
||||
|
||||
// These lists only contain itag formats that are supported by the common Android Video player.
|
||||
// How ever if you are heading for a list showing all itag formats lock at
|
||||
// How ever if you are heading for a list showing all itag formats look at
|
||||
// https://github.com/rg3/youtube-dl/issues/1687
|
||||
|
||||
public static int resolveFormat(int itag) {
|
||||
switch(itag) {
|
||||
// video
|
||||
case 17: return VideoInfo.I_3GPP;
|
||||
case 18: return VideoInfo.I_MPEG_4;
|
||||
case 22: return VideoInfo.I_MPEG_4;
|
||||
case 36: return VideoInfo.I_3GPP;
|
||||
case 37: return VideoInfo.I_MPEG_4;
|
||||
case 38: return VideoInfo.I_MPEG_4;
|
||||
case 43: return VideoInfo.I_WEBM;
|
||||
case 44: return VideoInfo.I_WEBM;
|
||||
case 45: return VideoInfo.I_WEBM;
|
||||
case 46: return VideoInfo.I_WEBM;
|
||||
case 17: return MediaFormat.v3GPP.id;
|
||||
case 18: return MediaFormat.MPEG_4.id;
|
||||
case 22: return MediaFormat.MPEG_4.id;
|
||||
case 36: return MediaFormat.v3GPP.id;
|
||||
case 37: return MediaFormat.MPEG_4.id;
|
||||
case 38: return MediaFormat.MPEG_4.id;
|
||||
case 43: return MediaFormat.WEBM.id;
|
||||
case 44: return MediaFormat.WEBM.id;
|
||||
case 45: return MediaFormat.WEBM.id;
|
||||
case 46: return MediaFormat.WEBM.id;
|
||||
default:
|
||||
//Log.i(TAG, "Itag " + Integer.toString(itag) + " not known or not supported.");
|
||||
return -1;
|
||||
@@ -93,38 +92,68 @@ public class YoutubeExtractor implements Extractor {
|
||||
}
|
||||
}
|
||||
|
||||
private String decryptoinCode = "";
|
||||
|
||||
// static values
|
||||
private static final String DECRYPTION_FUNC_NAME="decrypt";
|
||||
|
||||
// cached values
|
||||
private static volatile String decryptionCode = "";
|
||||
|
||||
public void initService(String site) {
|
||||
// The Youtube service needs to be initialized by downloading the
|
||||
// js-Youtube-player. This is done in order to get the algorithm
|
||||
// for decrypting cryptic signatures inside certain stream urls.
|
||||
|
||||
// Star Wars Kid is used as a dummy video, in order to download the youtube player.
|
||||
//String site = Downloader.download("https://www.youtube.com/watch?v=HPPj6viIBmU");
|
||||
//-------------------------------------
|
||||
// extracting form player args
|
||||
//-------------------------------------
|
||||
try {
|
||||
String jsonString = matchGroup1("ytplayer.config\\s*=\\s*(\\{.*?\\});", site);
|
||||
JSONObject jsonObj = new JSONObject(jsonString);
|
||||
|
||||
//----------------------------------
|
||||
// load and parse description code
|
||||
//----------------------------------
|
||||
if (decryptionCode.isEmpty()) {
|
||||
JSONObject ytAssets = jsonObj.getJSONObject("assets");
|
||||
String playerUrl = ytAssets.getString("js");
|
||||
if (playerUrl.startsWith("//")) {
|
||||
playerUrl = "https:" + playerUrl;
|
||||
}
|
||||
decryptionCode = loadDecryptionCode(playerUrl);
|
||||
}
|
||||
|
||||
} catch (Exception e){
|
||||
Log.d(TAG, "Could not initialize the extractor of the Youtube service.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVideoId(String videoUrl) {
|
||||
try {
|
||||
URI uri = new URI(videoUrl);
|
||||
if(uri.getHost().contains("youtube")) {
|
||||
String query = uri.getQuery();
|
||||
String queryElements[] = query.split("&");
|
||||
Map<String, String> queryArguments = new HashMap<>();
|
||||
for (String e : queryElements) {
|
||||
String[] s = e.split("=");
|
||||
queryArguments.put(s[0], s[1]);
|
||||
}
|
||||
return queryArguments.get("v");
|
||||
} else if(uri.getHost().contains("youtu.be")) {
|
||||
// uri.getRawPath() does somehow not return the last character.
|
||||
// so we do a workaround instead.
|
||||
//return uri.getRawPath();
|
||||
String url[] = videoUrl.split("/");
|
||||
return url[url.length-1];
|
||||
} else {
|
||||
Log.e(TAG, "Error could not parse url: " + videoUrl);
|
||||
String id = "";
|
||||
Pattern pat;
|
||||
|
||||
}
|
||||
} catch(Exception e) {
|
||||
if(videoUrl.contains("youtube")) {
|
||||
pat = Pattern.compile("youtube\\.com/watch\\?v=([\\-a-zA-Z0-9_]{11})");
|
||||
}
|
||||
else if(videoUrl.contains("youtu.be")) {
|
||||
pat = Pattern.compile("youtu\\.be/([a-zA-Z0-9_-]{11})");
|
||||
}
|
||||
else {
|
||||
Log.e(TAG, "Error could not parse url: " + videoUrl);
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
return null;
|
||||
Matcher mat = pat.matcher(videoUrl);
|
||||
boolean foundMatch = mat.find();
|
||||
if(foundMatch){
|
||||
id = mat.group(1);
|
||||
Log.i(TAG, "string \""+videoUrl+"\" matches!");
|
||||
}
|
||||
Log.i(TAG, "string \""+videoUrl+"\" does not match.");
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,35 +168,24 @@ public class YoutubeExtractor implements Extractor {
|
||||
|
||||
Document doc = Jsoup.parse(site, siteUrl);
|
||||
|
||||
try {
|
||||
Pattern p = Pattern.compile("v=([0-9a-zA-Z]*)");
|
||||
Matcher m = p.matcher(siteUrl);
|
||||
m.find();
|
||||
videoInfo.id = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
videoInfo.id = matchGroup1("v=([0-9a-zA-Z_-]{11})", siteUrl);
|
||||
|
||||
videoInfo.age_limit = 0;
|
||||
videoInfo.webpage_url = siteUrl;
|
||||
|
||||
initService(site);
|
||||
|
||||
//-------------------------------------
|
||||
// extracting form player args
|
||||
//-------------------------------------
|
||||
JSONObject playerArgs = null;
|
||||
JSONObject ytAssets = null;
|
||||
String dashManifest = "";
|
||||
{
|
||||
Pattern p = Pattern.compile("ytplayer.config\\s*=\\s*(\\{.*?\\});");
|
||||
Matcher m = p.matcher(site);
|
||||
m.find();
|
||||
|
||||
try {
|
||||
playerArgs = (new JSONObject(m.group(1)))
|
||||
.getJSONObject("args");
|
||||
ytAssets = (new JSONObject(m.group(1)))
|
||||
.getJSONObject("assets");
|
||||
}catch (Exception e) {
|
||||
String jsonString = matchGroup1("ytplayer.config\\s*=\\s*(\\{.*?\\});", site);
|
||||
JSONObject jsonObj = new JSONObject(jsonString);
|
||||
playerArgs = jsonObj.getJSONObject("args");
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// If we fail in this part the video is most likely not available.
|
||||
// Determining why is done later.
|
||||
@@ -175,26 +193,31 @@ public class YoutubeExtractor implements Extractor {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
// load and extract audio
|
||||
//-----------------------
|
||||
try {
|
||||
String dashManifest = playerArgs.getString("dashmpd");
|
||||
videoInfo.audioStreams = parseDashManifest(dashManifest, decryptionCode);
|
||||
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "Could not find \"dashmpd\" upon the player args (maybe no dash manifest available).");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
//--------------------------------------------
|
||||
// extract general information about the video
|
||||
//--------------------------------------------
|
||||
|
||||
videoInfo.uploader = playerArgs.getString("author");
|
||||
videoInfo.title = playerArgs.getString("title");
|
||||
//first attempt gating a small image version
|
||||
//first attempt getting a small image version
|
||||
//in the html extracting part we try to get a thumbnail with a higher resolution
|
||||
videoInfo.thumbnail_url = playerArgs.getString("thumbnail_url");
|
||||
videoInfo.duration = playerArgs.getInt("length_seconds");
|
||||
videoInfo.average_rating = playerArgs.getString("avg_rating");
|
||||
// View Count will be extracted from html
|
||||
dashManifest = playerArgs.getString("dashmpd");
|
||||
String playerUrl = ytAssets.getString("js");
|
||||
if(playerUrl.startsWith("//")) {
|
||||
playerUrl = "https:" + playerUrl;
|
||||
}
|
||||
if(decryptoinCode.isEmpty()) {
|
||||
decryptoinCode = loadDecryptioinCode(playerUrl);
|
||||
}
|
||||
|
||||
// extract audio
|
||||
videoInfo.audioStreams = parseDashManifest(dashManifest, decryptoinCode);
|
||||
|
||||
//------------------------------------
|
||||
// extract video stream url
|
||||
@@ -209,14 +232,11 @@ public class YoutubeExtractor implements Extractor {
|
||||
}
|
||||
|
||||
int itag = Integer.parseInt(tags.get("itag"));
|
||||
String streamUrl = terrible_unescape_workaround_fuck(tags.get("url"));
|
||||
String streamUrl = URLDecoder.decode(tags.get("url"), "UTF-8");
|
||||
|
||||
// if video has a signature: decrypt it and add it to the url
|
||||
if(tags.get("s") != null) {
|
||||
if(decryptoinCode.isEmpty()) {
|
||||
decryptoinCode = loadDecryptioinCode(playerUrl);
|
||||
}
|
||||
streamUrl = streamUrl + "&signature=" + decryptSignature(tags.get("s"), decryptoinCode);
|
||||
streamUrl = streamUrl + "&signature=" + decryptSignature(tags.get("s"), decryptionCode);
|
||||
}
|
||||
|
||||
if(resolveFormat(itag) != -1) {
|
||||
@@ -226,18 +246,16 @@ public class YoutubeExtractor implements Extractor {
|
||||
resolveResolutionString(itag)));
|
||||
}
|
||||
}
|
||||
videoInfo.videoStreams = new VideoInfo.VideoStream[videoStreams.size()];
|
||||
for(int i = 0; i < videoStreams.size(); i++) {
|
||||
videoInfo.videoStreams[i] = videoStreams.get(i);
|
||||
}
|
||||
videoInfo.videoStreams =
|
||||
videoStreams.toArray(new VideoInfo.VideoStream[videoStreams.size()]);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// extrating from html page
|
||||
//-------------------------------
|
||||
//---------------------------------------
|
||||
// extracting information from html page
|
||||
//---------------------------------------
|
||||
|
||||
|
||||
// Determine what went wrong when the Video is not available
|
||||
@@ -252,41 +270,37 @@ public class YoutubeExtractor implements Extractor {
|
||||
videoInfo.thumbnail_url = doc.select("link[itemprop=\"thumbnailUrl\"]").first()
|
||||
.attr("abs:href");
|
||||
} catch(Exception e) {
|
||||
Log.i(TAG, "Could not find high res Thumbnail. Use low res instead");
|
||||
Log.i(TAG, "Could not find high res Thumbnail. Using low res instead");
|
||||
}
|
||||
|
||||
// upload date
|
||||
videoInfo.upload_date = doc.select("strong[class=\"watch-time-text\"").first()
|
||||
.text();
|
||||
// Try to only use date not the text around it
|
||||
try {
|
||||
Pattern p = Pattern.compile("([0-9.]*$)");
|
||||
Matcher m = p.matcher(videoInfo.upload_date);
|
||||
m.find();
|
||||
videoInfo.upload_date = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
videoInfo.upload_date = doc.select("meta[itemprop=datePublished]").attr("content");
|
||||
|
||||
//TODO: Format date locale-specifically
|
||||
|
||||
|
||||
// description
|
||||
videoInfo.description = doc.select("p[id=\"eow-description\"]").first()
|
||||
.html();
|
||||
|
||||
videoInfo.description = doc.select("p[id=\"eow-description\"]").first().html();
|
||||
String likesString = "";
|
||||
String dislikesString = "";
|
||||
try {
|
||||
// likes
|
||||
videoInfo.like_count = doc.select("span[class=\"like-button-renderer \"]").first()
|
||||
.getAllElements().select("button")
|
||||
.select("span").get(0).text();
|
||||
|
||||
|
||||
likesString = doc.select("button.like-button-renderer-like-button").first()
|
||||
.select("span.yt-uix-button-content").first().text();
|
||||
videoInfo.like_count = Integer.parseInt(likesString.replaceAll("[^\\d]", ""));
|
||||
// dislikes
|
||||
videoInfo.dislike_count = doc.select("span[class=\"like-button-renderer \"]").first()
|
||||
.getAllElements().select("button")
|
||||
.select("span").get(2).text();
|
||||
dislikesString = doc.select("button.like-button-renderer-dislike-button").first()
|
||||
.select("span.yt-uix-button-content").first().text();
|
||||
|
||||
videoInfo.dislike_count = Integer.parseInt(dislikesString.replaceAll("[^\\d]", ""));
|
||||
} catch(NumberFormatException nfe) {
|
||||
Log.e(TAG, "failed to parse likesString \""+likesString+"\" and dislikesString \""+
|
||||
dislikesString+"\" as integers");
|
||||
} catch(Exception e) {
|
||||
// if it fails we know that the video does not offer dislikes.
|
||||
videoInfo.like_count = "0";
|
||||
videoInfo.dislike_count = "0";
|
||||
e.printStackTrace();
|
||||
videoInfo.like_count = 0;
|
||||
videoInfo.dislike_count = 0;
|
||||
}
|
||||
|
||||
// uploader thumbnail
|
||||
@@ -294,43 +308,31 @@ public class YoutubeExtractor implements Extractor {
|
||||
.select("img").first()
|
||||
.attr("abs:data-thumb");
|
||||
|
||||
// view count
|
||||
videoInfo.view_count = doc.select("div[class=\"watch-view-count\"]").first().text();
|
||||
|
||||
/* todo finish this code
|
||||
// view count TODO: locale-specific formatting
|
||||
String viewCountString = doc.select("meta[itemprop=interactionCount]").attr("content");
|
||||
videoInfo.view_count = Integer.parseInt(viewCountString);
|
||||
|
||||
// next video
|
||||
videoInfo.nextVideo = extractVideoInfoItem(doc.select("div[class=\"watch-sidebar-section\"]").first()
|
||||
.select("li").first());
|
||||
|
||||
int i = 0;
|
||||
// related videos
|
||||
Vector<VideoInfoItem> relatedVideos = new Vector<>();
|
||||
for(Element li : doc.select("ul[id=\"watch-related\"]").first().children()) {
|
||||
// first check if we have a playlist. If so leave them out
|
||||
if(li.select("a[class*=\"content-link\"]").first() != null) {
|
||||
//videoInfo.relatedVideos.add(extractVideoInfoItem(li));
|
||||
//i++;
|
||||
//Log.d(TAG, Integer.toString(i));
|
||||
relatedVideos.add(extractVideoInfoItem(li));
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
videoInfo.relatedVideos = relatedVideos.toArray(new VideoInfoItem[relatedVideos.size()]);
|
||||
return videoInfo;
|
||||
}
|
||||
|
||||
private VideoInfo.AudioStream[] parseDashManifest(String dashManifest, String decryptoinCode) {
|
||||
if(!dashManifest.contains("/signature/")) {
|
||||
String encryptedSig = "";
|
||||
String decryptedSig = "";
|
||||
try {
|
||||
Pattern p = Pattern.compile("/s/([a-fA-F0-9\\.]+)");
|
||||
Matcher m = p.matcher(dashManifest);
|
||||
m.find();
|
||||
encryptedSig = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String encryptedSig = matchGroup1("/s/([a-fA-F0-9\\.]+)", dashManifest);
|
||||
String decryptedSig;
|
||||
|
||||
decryptedSig = decryptSignature(encryptedSig, decryptoinCode);
|
||||
dashManifest = dashManifest.replace("/s/" + encryptedSig, "/signature/" + decryptedSig);
|
||||
}
|
||||
@@ -365,13 +367,13 @@ public class YoutubeExtractor implements Extractor {
|
||||
if(currentTagIsBaseUrl &&
|
||||
(currentMimeType.contains("audio"))) {
|
||||
int format = -1;
|
||||
if(currentMimeType.equals(VideoInfo.M_WEBMA)) {
|
||||
format = VideoInfo.I_WEBMA;
|
||||
} else if(currentMimeType.equals(VideoInfo.M_M4A)) {
|
||||
format = VideoInfo.I_M4A;
|
||||
if(currentMimeType.equals(MediaFormat.WEBMA.mimeType)) {
|
||||
format = MediaFormat.WEBMA.id;
|
||||
} else if(currentMimeType.equals(MediaFormat.M4A.mimeType)) {
|
||||
format = MediaFormat.M4A.id;
|
||||
}
|
||||
audioStreams.add(new VideoInfo.AudioStream(parser.getText(),
|
||||
format, currentBandwidth, currentSamplingRate));
|
||||
format, currentBandwidth, currentSamplingRate));
|
||||
}
|
||||
case XmlPullParser.END_TAG:
|
||||
if(tagName.equals("AdaptationSet")) {
|
||||
@@ -387,11 +389,7 @@ public class YoutubeExtractor implements Extractor {
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
VideoInfo.AudioStream[] output = new VideoInfo.AudioStream[audioStreams.size()];
|
||||
for(int i = 0; i < output.length; i++) {
|
||||
output[i] = audioStreams.get(i);
|
||||
}
|
||||
return output;
|
||||
return audioStreams.toArray(new VideoInfo.AudioStream[audioStreams.size()]);
|
||||
}
|
||||
|
||||
private VideoInfoItem extractVideoInfoItem(Element li) {
|
||||
@@ -399,18 +397,15 @@ public class YoutubeExtractor implements Extractor {
|
||||
info.webpage_url = li.select("a[class*=\"content-link\"]").first()
|
||||
.attr("abs:href");
|
||||
try {
|
||||
Pattern p = Pattern.compile("v=([0-9a-zA-Z-]*)");
|
||||
Matcher m = p.matcher(info.webpage_url);
|
||||
m.find();
|
||||
info.id=m.group(1);
|
||||
info.id = matchGroup1("v=([0-9a-zA-Z-]*)", info.webpage_url);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
info.title = li.select("span[class=\"title\"]").first()
|
||||
.text();
|
||||
|
||||
//todo: check NullPointerException causing
|
||||
info.title = li.select("span[class=\"title\"]").first().text();
|
||||
info.view_count = li.select("span[class*=\"view-count\"]").first().text();
|
||||
info.uploader = li.select("span[class=\"g-hovercard\"]").first().text();
|
||||
|
||||
info.duration = li.select("span[class=\"video-time\"]").first().text();
|
||||
|
||||
Element img = li.select("img").first();
|
||||
@@ -421,24 +416,13 @@ public class YoutubeExtractor implements Extractor {
|
||||
if(info.thumbnail_url.contains(".gif")) {
|
||||
info.thumbnail_url = img.attr("data-thumb");
|
||||
}
|
||||
|
||||
if(info.thumbnail_url.startsWith("//")) {
|
||||
info.thumbnail_url = "https:" + info.thumbnail_url;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private String terrible_unescape_workaround_fuck(String shit) {
|
||||
String[] splitAtEscape = shit.split("%");
|
||||
String retval = "";
|
||||
retval += splitAtEscape[0];
|
||||
for(int i = 1; i < splitAtEscape.length; i++) {
|
||||
String escNum = splitAtEscape[i].substring(0, 2);
|
||||
char c = (char) Integer.parseInt(escNum,16);
|
||||
retval += c;
|
||||
retval += splitAtEscape[i].substring(2);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private String loadDecryptioinCode(String playerUrl) {
|
||||
private String loadDecryptionCode(String playerUrl) {
|
||||
String playerCode = Downloader.download(playerUrl);
|
||||
String decryptionFuncName = "";
|
||||
String decryptionFunc = "";
|
||||
@@ -448,27 +432,16 @@ public class YoutubeExtractor implements Extractor {
|
||||
String decryptionCode;
|
||||
|
||||
try {
|
||||
Pattern p = Pattern.compile("\\.sig\\|\\|([a-zA-Z0-9$]+)\\(");
|
||||
Matcher m = p.matcher(playerCode);
|
||||
m.find();
|
||||
decryptionFuncName = m.group(1);
|
||||
decryptionFuncName = matchGroup1("\\.sig\\|\\|([a-zA-Z0-9$]+)\\(", playerCode);
|
||||
|
||||
String functionPattern = "(function " + decryptionFuncName.replace("$", "\\$") + "\\([a-zA-Z0-9_]*\\)\\{.+?\\})";
|
||||
p = Pattern.compile(functionPattern);
|
||||
m = p.matcher(playerCode);
|
||||
m.find();
|
||||
decryptionFunc = m.group(1);
|
||||
String functionPattern = "(var "+ decryptionFuncName.replace("$", "\\$") +"=function\\([a-zA-Z0-9_]*\\)\\{.+?\\})";
|
||||
decryptionFunc = matchGroup1(functionPattern, playerCode);
|
||||
decryptionFunc += ";";
|
||||
|
||||
p = Pattern.compile(";([A-Za-z0-9_\\$]{2})\\...\\(");
|
||||
m = p.matcher(decryptionFunc);
|
||||
m.find();
|
||||
helperObjectName = m.group(1);
|
||||
helperObjectName = matchGroup1(";([A-Za-z0-9_\\$]{2})\\...\\(", decryptionFunc);
|
||||
|
||||
String helperPattern = "(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)function";
|
||||
p = Pattern.compile(helperPattern);
|
||||
m = p.matcher(playerCode);
|
||||
m.find();
|
||||
helperObject = m.group(1);
|
||||
String helperPattern = "(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)";
|
||||
helperObject = matchGroup1(helperPattern, playerCode);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -480,13 +453,13 @@ public class YoutubeExtractor implements Extractor {
|
||||
return decryptionCode;
|
||||
}
|
||||
|
||||
private String decryptSignature(String encryptedSig, String decryptoinCode) {
|
||||
private String decryptSignature(String encryptedSig, String decryptionCode) {
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
Object result = null;
|
||||
try {
|
||||
ScriptableObject scope = context.initStandardObjects();
|
||||
context.evaluateString(scope, decryptoinCode, "decryptionCode", 1, null);
|
||||
context.evaluateString(scope, decryptionCode, "decryptionCode", 1, null);
|
||||
Function decryptionFunc = (Function) scope.get("decrypt", scope);
|
||||
result = decryptionFunc.call(context, scope, scope, new Object[]{encryptedSig});
|
||||
} catch (Exception e) {
|
||||
@@ -495,4 +468,19 @@ public class YoutubeExtractor implements Extractor {
|
||||
Context.exit();
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private String matchGroup1(String pattern, String input) {
|
||||
Pattern pat = Pattern.compile(pattern);
|
||||
Matcher mat = pat.matcher(input);
|
||||
boolean foundMatch = mat.find();
|
||||
if(foundMatch){
|
||||
return mat.group(1);
|
||||
}
|
||||
else {
|
||||
Log.e(TAG, "failed to find pattern \""+pattern+"\" inside of \""+input+"\"");
|
||||
new Exception("failed to find pattern \""+pattern+"\"").printStackTrace();
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
package org.schabi.newpipe.youtube;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.SearchEngine;
|
||||
import org.schabi.newpipe.VideoInfoItem;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.SearchEngine;
|
||||
import org.schabi.newpipe.VideoInfoItem;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 09.08.15.
|
||||
@@ -39,7 +49,8 @@ public class YoutubeSearchEngine implements SearchEngine {
|
||||
private static final String TAG = YoutubeSearchEngine.class.toString();
|
||||
|
||||
@Override
|
||||
public Result search(String query, int page) {
|
||||
public Result search(String query, int page, String languageCode) {
|
||||
//String contentCountry = PreferenceManager.getDefaultSharedPreferences(this).getString(getString(R.string., "");
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme("https")
|
||||
.authority("www.youtube.com")
|
||||
@@ -47,9 +58,19 @@ public class YoutubeSearchEngine implements SearchEngine {
|
||||
.appendQueryParameter("search_query", query)
|
||||
.appendQueryParameter("page", Integer.toString(page))
|
||||
.appendQueryParameter("filters", "video");
|
||||
String url = builder.build().toString();
|
||||
|
||||
String site = Downloader.download(url);
|
||||
String site;
|
||||
String url = builder.build().toString();
|
||||
//if we've been passed a valid language code, append it to the URL
|
||||
if(languageCode.length() > 0) {
|
||||
//assert Pattern.matches("[a-z]{2}(-([A-Z]{2}|[0-9]{1,3}))?", languageCode);
|
||||
site = Downloader.download(url, languageCode);
|
||||
}
|
||||
else {
|
||||
site = Downloader.download(url);
|
||||
}
|
||||
|
||||
|
||||
Document doc = Jsoup.parse(site, url);
|
||||
Result result = new Result();
|
||||
Element list = doc.select("ol[class=\"item-section\"]").first();
|
||||
@@ -58,14 +79,14 @@ public class YoutubeSearchEngine implements SearchEngine {
|
||||
int i = 0;
|
||||
for(Element item : list.children()) {
|
||||
i++;
|
||||
/* First we need to determine witch kind of item we are working with.
|
||||
Youtube depicts fife different kinds if items at its search result page. These are
|
||||
regular videos, playlists, channels, two types of video suggestions, and a no video
|
||||
found item. Since we only want videos, we net to filter out all the others.
|
||||
/* First we need to determine which kind of item we are working with.
|
||||
Youtube depicts five different kinds of items on its search result page. These are
|
||||
regular videos, playlists, channels, two types of video suggestions, and a "no video
|
||||
found" item. Since we only want videos, we need to filter out all the others.
|
||||
An example for this can be seen here:
|
||||
https://www.youtube.com/results?search_query=asdf&page=1
|
||||
|
||||
We already applied a filter to the url, so we don't need to care about channels, and
|
||||
We already applied a filter to the url, so we don't need to care about channels and
|
||||
playlists now.
|
||||
*/
|
||||
|
||||
@@ -103,9 +124,9 @@ public class YoutubeSearchEngine implements SearchEngine {
|
||||
Element te = item.select("div[class=\"yt-thumb video-thumb\"]").first()
|
||||
.select("img").first();
|
||||
resultItem.thumbnail_url = te.attr("abs:src");
|
||||
// Sometimes youtube sends links to gif files witch somehow seam to not exist
|
||||
// Sometimes youtube sends links to gif files which somehow seem to not exist
|
||||
// anymore. Items with such gif also offer a secondary image source. So we are going
|
||||
// to use that if we caught such an item.
|
||||
// to use that if we've caught such an item.
|
||||
if(resultItem.thumbnail_url.contains(".gif")) {
|
||||
resultItem.thumbnail_url = te.attr("abs:data-thumb");
|
||||
}
|
||||
@@ -114,7 +135,55 @@ public class YoutubeSearchEngine implements SearchEngine {
|
||||
Log.e(TAG, "GREAT FUCKING ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> suggestionList(String query) {
|
||||
|
||||
ArrayList<String> suggestions = new ArrayList<>();
|
||||
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme("https")
|
||||
.authority("suggestqueries.google.com")
|
||||
.appendPath("complete")
|
||||
.appendPath("search")
|
||||
.appendQueryParameter("client", "")
|
||||
.appendQueryParameter("output", "toolbar")
|
||||
.appendQueryParameter("ds", "yt")
|
||||
.appendQueryParameter("q", query);
|
||||
String url = builder.build().toString();
|
||||
|
||||
String response = Downloader.download(url);
|
||||
|
||||
//TODO: Parse xml data using Jsoup not done
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder;
|
||||
org.w3c.dom.Document doc = null;
|
||||
|
||||
try {
|
||||
dBuilder = dbFactory.newDocumentBuilder();
|
||||
doc = dBuilder.parse(new InputSource(new ByteArrayInputStream(response.getBytes("utf-8"))));
|
||||
doc.getDocumentElement().normalize();
|
||||
}catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if(doc!=null){
|
||||
NodeList nList = doc.getElementsByTagName("CompleteSuggestion");
|
||||
for (int temp = 0; temp < nList.getLength(); temp++) {
|
||||
|
||||
NodeList nList1 = doc.getElementsByTagName("suggestion");
|
||||
Node nNode1 = nList1.item(temp);
|
||||
if (nNode1.getNodeType() == Node.ELEMENT_NODE) {
|
||||
org.w3c.dom.Element eElement = (org.w3c.dom.Element) nNode1;
|
||||
suggestions.add(eElement.getAttribute("data"));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
Log.e(TAG, "GREAT FUCKING ERROR");
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.schabi.newpipe.youtube;
|
||||
|
||||
import org.schabi.newpipe.StreamingService;
|
||||
import org.schabi.newpipe.Extractor;
|
||||
import org.schabi.newpipe.SearchEngine;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 23.08.15.
|
||||
@@ -30,12 +33,12 @@ public class YoutubeService implements StreamingService {
|
||||
return serviceInfo;
|
||||
}
|
||||
@Override
|
||||
public Class getExtractorClass() {
|
||||
return YoutubeExtractor.class;
|
||||
public Extractor getExtractorInstance() {
|
||||
return new YoutubeExtractor();
|
||||
}
|
||||
@Override
|
||||
public Class getSearchEngineClass() {
|
||||
return YoutubeSearchEngine.class;
|
||||
public SearchEngine getSearchEngineInstance() {
|
||||
return new YoutubeSearchEngine();
|
||||
}
|
||||
@Override
|
||||
public boolean acceptUrl(String videoUrl) {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/drawable/ic_file_download_black.png
Normal file
|
After Width: | Height: | Size: 209 B |
@@ -6,33 +6,34 @@
|
||||
style="?android:attr/textAppearanceLarge"
|
||||
tools:context=".VideoItemDetailFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/videoitem_detail">
|
||||
|
||||
<ProgressBar android:id="@+id/detailProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/videoitem_detail"
|
||||
android:id="@+id/detailMainContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textIsSelectable="true">
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="invisible">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<ProgressBar android:id="@+id/detailProgressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
<ImageView android:id="@+id/detailThumbnailView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/dummi_thumbnail"
|
||||
android:visibility="invisible"/>
|
||||
android:src="@drawable/dummy_thumbnail"/>
|
||||
|
||||
<TextView android:id="@+id/detailVideoTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -40,19 +41,19 @@
|
||||
android:layout_below="@id/detailThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="Bla blabla !!!"
|
||||
android:visibility="invisible"/>
|
||||
android:text="Bla blabla !!!"/>
|
||||
|
||||
<ImageView android:id="@+id/detailUploaderThumbnailView"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="100dp"
|
||||
android:paddingTop="25dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:layout_below="@id/detailVideoTitleView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/budy" />
|
||||
android:src="@drawable/buddy" />
|
||||
|
||||
<TextView android:id="@+id/detailUploaderView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -60,8 +61,8 @@
|
||||
android:layout_below="@id/detailUploaderThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="Herr von Gurken" />
|
||||
|
||||
<View android:id="@+id/textSeperationLine"
|
||||
@@ -70,7 +71,6 @@
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailUploaderView"
|
||||
android:paddingTop="20dp"
|
||||
android:visibility="invisible"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<TextView android:id="@+id/detailViewCountView"
|
||||
@@ -80,7 +80,6 @@
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingTop="70dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible"
|
||||
android:text="1.000.115 views" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsDownCountView"
|
||||
@@ -89,7 +88,6 @@
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="5.000" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsDownImgView"
|
||||
@@ -97,7 +95,6 @@
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownCountView"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/thumbs_down" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsUpCountView"
|
||||
@@ -106,7 +103,6 @@
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownImgView"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="111.111" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsUpImgView"
|
||||
@@ -114,7 +110,6 @@
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsUpCountView"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/thumbs_up" />
|
||||
|
||||
<TextView android:id="@+id/detailUploadDateView"
|
||||
@@ -123,9 +118,9 @@
|
||||
android:layout_below="@id/detailUploaderView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible"
|
||||
android:text="Uploaded at: 45.64.1285" />
|
||||
|
||||
<TextView android:id="@+id/detailDescriptionView"
|
||||
@@ -134,15 +129,77 @@
|
||||
android:layout_below="@id/detailUploadDateView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmodtempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. "
|
||||
/>
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVideoRootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailDescriptionView" >
|
||||
|
||||
<TextView android:id="@+id/detailNextVideoTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="@android:color/black"
|
||||
android:text="@string/nextVideoTitle"
|
||||
/>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLine"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVideoTitle"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailNextVideoSeperationLine">
|
||||
<FrameLayout
|
||||
android:id="@+id/detailNextVideoFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<Button
|
||||
android:id="@+id/detailNextVideoButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@id/detailNextVideoFrame"
|
||||
android:layout_alignBottom="@id/detailNextVideoFrame"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLineEnd"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_alignParentLeft="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<Button android:id="@+id/detailShowSimilarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:layout_below="@id/detailNextVideoRootLayout"
|
||||
android:text="@string/showSimilarVideosButtonText"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_below="@id/detailDescriptionView"/>
|
||||
android:layout_height="90dp"
|
||||
android:layout_below="@id/detailShowSimilarButton"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
@@ -155,5 +212,5 @@
|
||||
android:layout_height="wrap_content"
|
||||
app:backgroundTint="@color/primaryColorYoutube"
|
||||
android:src="@drawable/ic_play_arrow_black"
|
||||
android:layout_margin="15pt"/>
|
||||
android:layout_margin="16dip"/>
|
||||
</RelativeLayout>
|
||||
@@ -42,12 +42,6 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="4">
|
||||
|
||||
<ImageView android:id="@+id/list_view_watermark"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="10dp"
|
||||
android:src="@drawable/new_pipe_watermark"/>
|
||||
|
||||
<FrameLayout android:id="@+id/videoitem_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
216
app/src/main/res/layout-sw600dp/fragment_videoitem_detail.xml
Normal file
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="?android:attr/textAppearanceLarge"
|
||||
tools:context=".VideoItemDetailFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/videoitem_detail">
|
||||
|
||||
<ProgressBar android:id="@+id/detailProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/detailMainContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="invisible">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView android:id="@+id/detailThumbnailView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/dummy_thumbnail"/>
|
||||
|
||||
<TextView android:id="@+id/detailVideoTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="Bla blabla !!!"/>
|
||||
|
||||
<ImageView android:id="@+id/detailUploaderThumbnailView"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="100dp"
|
||||
android:paddingTop="25dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:layout_below="@id/detailVideoTitleView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:src="@drawable/buddy" />
|
||||
|
||||
<TextView android:id="@+id/detailUploaderView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailUploaderThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Herr von Gurken" />
|
||||
|
||||
<View android:id="@+id/textSeperationLine"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailUploaderView"
|
||||
android:paddingTop="20dp"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<TextView android:id="@+id/detailViewCountView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailVideoTitleView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingTop="70dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="1.000.115 views" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsDownCountView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="5.000" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsDownImgView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownCountView"
|
||||
android:src="@drawable/thumbs_down" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsUpCountView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownImgView"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="111.111" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsUpImgView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsUpCountView"
|
||||
android:src="@drawable/thumbs_up" />
|
||||
|
||||
<TextView android:id="@+id/detailUploadDateView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailUploaderView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="Uploaded at: 45.64.1285" />
|
||||
|
||||
<TextView android:id="@+id/detailDescriptionView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailUploadDateView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmodtempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. "
|
||||
/>
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVideoRootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailDescriptionView" >
|
||||
|
||||
<TextView android:id="@+id/detailNextVideoTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="@android:color/black"
|
||||
android:text="@string/nextVideoTitle"
|
||||
/>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLine"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVideoTitle"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailNextVideoSeperationLine">
|
||||
<FrameLayout
|
||||
android:id="@+id/detailNextVideoFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<Button
|
||||
android:id="@+id/detailNextVideoButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@id/detailNextVideoFrame"
|
||||
android:layout_alignBottom="@id/detailNextVideoFrame"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLineEnd"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_alignParentLeft="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<Button android:id="@+id/detailShowSimilarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:layout_below="@id/detailNextVideoRootLayout"
|
||||
android:text="@string/showSimilarVideosButtonText"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="90dp"
|
||||
android:layout_below="@id/detailShowSimilarButton"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/playVideoButton"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:backgroundTint="@color/primaryColorYoutube"
|
||||
android:src="@drawable/ic_play_arrow_black"
|
||||
android:layout_margin="16dip"/>
|
||||
</RelativeLayout>
|
||||
@@ -3,12 +3,6 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView android:id="@+id/list_view_watermark"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="10dp"
|
||||
android:src="@drawable/new_pipe_watermark"/>
|
||||
|
||||
<fragment
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/videoitem_list"
|
||||
|
||||
@@ -7,21 +7,24 @@
|
||||
android:textIsSelectable="true"
|
||||
style="?android:attr/textAppearanceLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/videoitem_detail">
|
||||
|
||||
<ProgressBar android:id="@+id/detailProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/videoitem_detail"
|
||||
android:id="@+id/detailMainContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar android:id="@+id/detailProgressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"/>
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView android:id="@+id/detailThumbnailView"
|
||||
android:layout_width="match_parent"
|
||||
@@ -30,8 +33,7 @@
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/dummi_thumbnail"/>
|
||||
android:src="@drawable/dummy_thumbnail"/>
|
||||
|
||||
<TextView android:id="@+id/detailVideoTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -39,20 +41,22 @@
|
||||
android:layout_below="@id/detailThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingTop="3dp"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible"
|
||||
android:text="Bla blabla !!!"/>
|
||||
android:text="Video title placeholder"/>
|
||||
|
||||
<ImageView android:id="@+id/detailUploaderThumbnailView"
|
||||
android:layout_width="85dp"
|
||||
android:layout_height="100dp"
|
||||
android:paddingTop="25dp"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:layout_below="@id/detailVideoTitleView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/budy" />
|
||||
android:src="@drawable/buddy" />
|
||||
|
||||
<TextView android:id="@+id/detailUploaderView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -60,20 +64,23 @@
|
||||
android:layout_below="@id/detailUploaderThumbnailView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="Herr von Gurken" />
|
||||
android:paddingRight="6dp"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/text_video_uploader_size"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="username" />
|
||||
|
||||
<TextView android:id="@+id/detailViewCountView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="25dp"
|
||||
android:paddingTop="6dp"
|
||||
android:layout_below="@id/detailVideoTitleView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:textSize="@dimen/text_video_visits_size"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible"
|
||||
android:text="drölf views" />
|
||||
android:text="81,754 views" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsDownCountView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -81,16 +88,16 @@
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:textSize="@dimen/text_video_like_size"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="-5.000" />
|
||||
android:text="100" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsDownImgView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownCountView"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/thumbs_down" />
|
||||
|
||||
<TextView android:id="@+id/detailThumbsUpCountView"
|
||||
@@ -98,16 +105,15 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsDownImgView"
|
||||
android:textSize="@dimen/text_video_like_size"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="∞" />
|
||||
android:text="20" />
|
||||
|
||||
<ImageView android:id="@+id/detailThumbsUpImgView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_below="@id/detailViewCountView"
|
||||
android:layout_toLeftOf="@id/detailThumbsUpCountView"
|
||||
android:visibility="invisible"
|
||||
android:src="@drawable/thumbs_up" />
|
||||
|
||||
<TextView android:id="@+id/detailUploadDateView"
|
||||
@@ -116,29 +122,95 @@
|
||||
android:layout_below="@id/detailUploaderView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="0dp"
|
||||
android:textSize="@dimen/text_video_uploadtime_size"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible"
|
||||
android:text="Uploaded at: 45.64.1285" />
|
||||
android:text="Published on Jan 01 1975" />
|
||||
|
||||
<TextView android:id="@+id/detailDescriptionView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailUploadDateView"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textSize="@dimen/text_video_description_size"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="invisible"
|
||||
android:text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmodtempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. "
|
||||
/>
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVideoRootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailDescriptionView" >
|
||||
|
||||
<TextView android:id="@+id/detailNextVideoTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="@android:color/black"
|
||||
android:text="@string/nextVideoTitle"
|
||||
/>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLine"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVideoTitle"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<RelativeLayout android:id="@+id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/detailNextVideoSeperationLine">
|
||||
<FrameLayout
|
||||
android:id="@+id/detailNextVideoFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<Button
|
||||
android:id="@+id/detailNextVideoButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@id/detailNextVideoFrame"
|
||||
android:layout_alignBottom="@id/detailNextVideoFrame"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<View android:id="@+id/detailNextVideoSeperationLineEnd"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_below="@id/detailNextVidButtonAndContantLayout"
|
||||
android:layout_alignParentLeft="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<Button android:id="@+id/detailShowSimilarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:layout_below="@id/detailNextVideoRootLayout"
|
||||
android:text="@string/showSimilarVideosButtonText"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_below="@id/detailDescriptionView"/>
|
||||
android:layout_height="90dp"
|
||||
android:layout_below="@id/detailShowSimilarButton"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/playVideoButton"
|
||||
android:layout_alignParentBottom="true"
|
||||
@@ -147,5 +219,5 @@
|
||||
android:layout_height="wrap_content"
|
||||
app:backgroundTint="@color/primaryColorYoutube"
|
||||
android:src="@drawable/ic_play_arrow_black"
|
||||
android:layout_margin="15pt"/>
|
||||
android:layout_margin="20dp"/>
|
||||
</RelativeLayout>
|
||||
@@ -7,11 +7,12 @@
|
||||
android:padding="6dp">
|
||||
|
||||
<ImageView android:id="@+id/itemThumbnailView"
|
||||
android:layout_width="125dp"
|
||||
android:layout_width="142dp"
|
||||
android:layout_height="80dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:src="@drawable/dummi_thumbnail"/>
|
||||
android:src="@drawable/dummy_thumbnail"/>
|
||||
|
||||
<TextView android:id="@+id/itemVideoTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/menu_item_play"
|
||||
android:title="@string/play"
|
||||
app:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_play_arrow_black"/>
|
||||
|
||||
<item android:id="@+id/menu_item_play_audio"
|
||||
android:title="@string/playAudio"
|
||||
app:showAsAction="always"
|
||||
app:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_headset_black" />
|
||||
|
||||
<item android:id="@+id/menu_item_download"
|
||||
app:showAsAction="ifRoom"
|
||||
android:title="@string/download"
|
||||
android:icon="@drawable/ic_file_download_black"/>
|
||||
|
||||
<item android:id="@+id/menu_item_share"
|
||||
android:title="@string/share"
|
||||
app:showAsAction="ifRoom"
|
||||
@@ -25,10 +26,6 @@
|
||||
app:showAsAction="never"
|
||||
android:title="@string/open_in_browser" />
|
||||
|
||||
<item android:id="@+id/menu_item_download"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/download"/>
|
||||
|
||||
<item android:id="@+id/action_settings"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/settings"/>
|
||||
|
||||
9
app/src/main/res/menu/videoitem_two_pannel.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:id="@+id/action_settings"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/settings"/>
|
||||
|
||||
</menu>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">Nichts gefunden</string>
|
||||
<string name="viewSufix">views</string>
|
||||
<string name="uploadDatePrefix">Hochgeladen am: </string>
|
||||
<string name="viewSufix">Aufrufe</string>
|
||||
<string name="uploadDatePrefix">Hochgeladen am </string>
|
||||
<string name="noPlayerFound">Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren.</string>
|
||||
<string name="installStreamPlayer">Jetzt installieren</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
@@ -26,7 +26,7 @@
|
||||
<string name="downloadLocation">Download Verzeichnis</string>
|
||||
<string name="downloadLocationSummary">Verzeichnis in dem heruntergeladene Videos gespeichert werden.</string>
|
||||
<string name="downloadLocationDialogTitle">Download Verzeichnis eingeben</string>
|
||||
<string name="autoPlayThroughIntentTitle">Automatisch abspielen durch Intent.</string>
|
||||
<string name="autoPlayThroughIntentTitle">Automatisches abspielen durch Intent</string>
|
||||
<string name="autoPlayThroughIntentSummary">Startet ein Video automatisch wenn es von einer anderen App aufgerufen wurde.</string>
|
||||
<string name="defaultResolutionPreferenceTitle">Standard Auflösung</string>
|
||||
<string name="playWithKodiTitle">Mit Kodi abspielen</string>
|
||||
@@ -45,4 +45,8 @@
|
||||
<item>Video</item>
|
||||
<item>Audio</item>
|
||||
</string-array>
|
||||
<string name="nextVideoTitle">Nächstes Video</string>
|
||||
<string name="showNextAndSimilarTitle">Zeige nächstes und änliche Videos</string>
|
||||
<string name="urlNotSupportedText">URL wird nicht unterstützt.</string>
|
||||
<string name="showSimilarVideosButtonText">Ähnliche Videos</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">No se ha encontrado nada</string>
|
||||
<string name="viewSufix">visitas</string>
|
||||
<string name="uploadDatePrefix">Subido desde: </string>
|
||||
<string name="uploadDatePrefix">Subido el </string>
|
||||
<string name="noPlayerFound">No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno.</string>
|
||||
<string name="installStreamPlayer">Instalar</string>
|
||||
<string name="installStreamPlayer">Instalarlo</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="fdroidVLCurl">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
|
||||
<string name="open_in_browser">Abrir en navegador</string>
|
||||
<string name="open_in_browser">Abrir en el navegador</string>
|
||||
<string name="share">Compartir</string>
|
||||
<string name="play">Reproducir</string>
|
||||
<string name="download">Descargar</string>
|
||||
<string name="search">Buscar</string>
|
||||
<string name="settings">Ajustes</string>
|
||||
<string name="sendWith">Enviar con</string>
|
||||
<string name="didYouMean">Querias decir: </string>
|
||||
<string name="didYouMean">"¿Querías decir?: "</string>
|
||||
<string name="searchPage">Buscar página: </string>
|
||||
<string name="shareDialogTitle">Compartir con:</string>
|
||||
<string name="chooseBrowser">Selecciona navegador:</string>
|
||||
@@ -24,15 +24,26 @@
|
||||
<string name="title_activity_settings">Ajustes</string>
|
||||
<string name="useExternalPlayerTitle">Usar reproductor externo</string>
|
||||
<string name="downloadLocation">Descargar en...</string>
|
||||
<string name="downloadLocationSummary">Donde se guardarán los vídeos descargados.</string>
|
||||
<string name="downloadLocationSummary">Ruta donde guardar los vídeos descargados.</string>
|
||||
<string name="downloadLocationDialogTitle">Localización del directorio de descargas</string>
|
||||
<string name="autoPlayThroughIntentTitle">Reproducción automática</string>
|
||||
<string name="autoPlayThroughIntentSummary">Reproduce los vídeos automaticamente cuando la llamada viene de otra aplicación.</string>
|
||||
<string name="autoPlayThroughIntentSummary">Reproducir los vídeos automaticamente cuando se llama desde otra aplicación.</string>
|
||||
<string name="defaultResolutionPreferenceTitle">Resolución por defecto</string>
|
||||
<string name="playWithKodiTitle">Reproducir con Kodi</string>
|
||||
<string name="koreNotFound">Aplicación Kore no encontrada. Kore es necesario para reproducir vídeos con Kodi media center.</string>
|
||||
<string name="installeKore">Instalar Kore</string>
|
||||
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore</string>
|
||||
<string name="showPlayWithKodiTitle">Mostrar la opción \"Reproducir con Kodi\"</string>
|
||||
<string name="showPlayWithKodiSummary">Muestra una opción para reproducir vídeo vía Kodi media center.</string>
|
||||
<string name="showPlayWithKodiSummary">Muestra una opción para reproducir el vídeo con Kodi media center.</string>
|
||||
<string name="leftPlayButtonTitle">Mostrar el botón de reproducir en el lado izquierdo.</string>
|
||||
<string name="playAudio">Audio</string>
|
||||
<string name="defaultAudioFormatTitle">Formato de audio por defecto</string>
|
||||
<string name="webMAudioDescription">WebM - formato libre</string>
|
||||
<string name="m4aAudioDescription">m4a - mejor calidad</string>
|
||||
<string name="downloadDialogTitle">Descargar</string>
|
||||
<string name="nextVideoTitle">Siguiente vídeo</string>
|
||||
<string name="showNextVideoTitle">Mostrar la opción \"Siguiente vídeo\".</string>
|
||||
<string name="urlNotSupportedText">URL no soportada.</string>
|
||||
<string name="showSimilarVideosButtonText">Vídeos similares</string>
|
||||
<string name="contentCountryTitle">País del contenido del vídeo</string>
|
||||
</resources>
|
||||
|
||||
51
app/src/main/res/values-fa/strings.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">چیزی پیدا نشد</string>
|
||||
<string name="viewSufix">نماها</string>
|
||||
<string name="uploadDatePrefix">بارگذاریشده در: </string>
|
||||
<string name="noPlayerFound">هیچ پخشکنندهی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید.</string>
|
||||
<string name="installStreamPlayer">نصب کنید</string>
|
||||
<string name="cancel">انصراف</string>
|
||||
<string name="fdroidVLCurl">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
|
||||
<string name="open_in_browser">بازکردن در مرورگر</string>
|
||||
<string name="share">همرسانی</string>
|
||||
<string name="play">پخش</string>
|
||||
<string name="download">بارگیری</string>
|
||||
<string name="search">جستجو</string>
|
||||
<string name="settings">تنظیمات</string>
|
||||
<string name="sendWith">فرستادن با</string>
|
||||
<string name="didYouMean">منظورتان این است: </string>
|
||||
<string name="searchPage">صفحهی جستجو: </string>
|
||||
<string name="shareDialogTitle">همرسانی با:</string>
|
||||
<string name="chooseBrowser">مرورگر را برگزینید:</string>
|
||||
<string name="screenRotation">چرخش</string>
|
||||
<string name="title_activity_settings">تنظیمات</string>
|
||||
<string name="useExternalPlayerTitle">استفاده از پخشکنندهی خارجی</string>
|
||||
<string name="downloadLocation">محل بارگیری</string>
|
||||
<string name="downloadLocationSummary">مسیری که ویدئوهای دریافت شده در آن ذخیره میشوند.</string>
|
||||
<string name="downloadLocationDialogTitle">مسیر دریافت را وارد کنید</string>
|
||||
<string name="autoPlayThroughIntentTitle">پخش خودکار از Intent</string>
|
||||
<string name="autoPlayThroughIntentSummary">ویدئو هنگامی که از برنامهی دیگری فراخوانده شد خودکار پخش میشود.</string>
|
||||
<string name="defaultResolutionPreferenceTitle">وضوح پیشفرض</string>
|
||||
<string name="playWithKodiTitle">پخش با Kodi</string>
|
||||
<string name="koreNotFound">برنامهی Kore نصب نیست. برای پخش کردن ویدئوها با مرکز رسانهی Kodi، به Kore نیاز دارید.</string>
|
||||
<string name="installeKore">نصب Kore</string>
|
||||
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore</string>
|
||||
<string name="showPlayWithKodiTitle">نمایش گزینهی «پخش با Kodi»</string>
|
||||
<string name="showPlayWithKodiSummary">گزینهای برای پخش کردن ویدئو با مرکز رسانهی Kodi نشان میدهد.</string>
|
||||
<string name="leftPlayButtonTitle">نمایش دکمهی پخش در سمت چپ.</string>
|
||||
<string name="playAudio">صدا</string>
|
||||
<string name="defaultAudioFormatTitle">قالب پیشفرض صدا</string>
|
||||
<string name="webMAudioDescription">WebM - قالبی آزاد</string>
|
||||
<string name="m4aAudioDescription">m4a - کیفیت بهتر</string>
|
||||
<string name="downloadDialogTitle">دریافت</string>
|
||||
<string-array name="downloadOptions">
|
||||
<item>ویدئو</item>
|
||||
<item>صدا</item>
|
||||
</string-array>
|
||||
<string name="nextVideoTitle">ویدئوی بعدی</string>
|
||||
<string name="showNextVideoTitle">نمایش گزینهی «ویدئوی بعدی».</string>
|
||||
<string name="urlNotSupportedText">پیوند پشتیبانی نمیشود.</string>
|
||||
</resources>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="autoPlayThroughIntentSummary">Démarrer automatiquement la vidéo si elle a été appellée à partir d\'une autre application.</string>
|
||||
@@ -16,10 +16,10 @@
|
||||
<string name="installeKore">Installer Kore</string>
|
||||
<string name="koreNotFound">L\'application Kore est introuvable. Kore est nécessaire afin de lire des vidéos dans Kodi media center.</string>
|
||||
<string name="noPlayerFound">Aucun lecteur de streaming détecté. Vous devriez en installer un.</string>
|
||||
<string name="nothingFound">Aucun résultat.</string>
|
||||
<string name="nothingFound">Aucun résultat</string>
|
||||
<string name="open_in_browser">Ouvrir dans le navigateur</string>
|
||||
<string name="play">Lire</string>
|
||||
<string name="autoPlayThroughIntentTitle">Lecture automatique via Intent.</string>
|
||||
<string name="autoPlayThroughIntentTitle">Lecture automatique via Intent</string>
|
||||
<string name="playWithKodiTitle">Lire avec Kodi</string>
|
||||
<string name="screenRotation">rotation</string>
|
||||
<string name="search">Chercher</string>
|
||||
@@ -32,7 +32,7 @@
|
||||
<string name="showPlayWithKodiTitle">Afficher l\'option \"Lire avec Kodi\"</string>
|
||||
<string name="title_activity_settings">Paramètres</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="uploadDatePrefix">Envoyé le:</string>
|
||||
<string name="uploadDatePrefix">Mise en ligne le </string>
|
||||
<string name="useExternalPlayerTitle">Utiliser un lecteur externe</string>
|
||||
<string name="viewSufix">vues</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
@@ -45,4 +45,8 @@
|
||||
<item>Videó</item>
|
||||
<item>Hang</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
<string name="nextVideoTitle">Következő videó</string>
|
||||
<string name="showNextVideoTitle">\"Következő videó\" elem mutatása</string>
|
||||
<string name="urlNotSupportedText">A webcím nem támogatott.</string>
|
||||
<string name="showSimilarVideosButtonText">Hasonló videók</string>
|
||||
</resources>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">Geen resultaten</string>
|
||||
<string name="viewSufix">keer bekeken</string>
|
||||
<string name="uploadDatePrefix">Geüpload op: </string>
|
||||
<string name="noPlayerFound">Geen speler met streaming ondersteuning gevonden. Je wilt er misschien een installeren.</string>
|
||||
<string name="uploadDatePrefix">Geüpload op </string>
|
||||
<string name="noPlayerFound">Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren.</string>
|
||||
<string name="installStreamPlayer">Installeer speler</string>
|
||||
<string name="cancel">Annuleer</string>
|
||||
<string name="fdroidVLCurl">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
|
||||
@@ -35,4 +35,16 @@
|
||||
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore</string>
|
||||
<string name="showPlayWithKodiTitle">Toon \"Speel af met Kodi\" optie</string>
|
||||
<string name="showPlayWithKodiSummary">Toont een optie om een video op een Kodi media center af te spelen.</string>
|
||||
</resources>
|
||||
<string name="contentCountryTitle">Video inhoud land</string>
|
||||
<string name="leftPlayButtonTitle">Afspeel knop aan de linker kant weergeven.</string>
|
||||
<string name="playAudio">Audio</string>
|
||||
<string name="defaultAudioFormatTitle">Standaard audio formaat</string>
|
||||
<string name="webMAudioDescription">Webam - open formaat</string>
|
||||
<string name="m4aAudioDescription">m4a - betere kwaliteit</string>
|
||||
<string name="downloadDialogTitle">Download</string>
|
||||
<string name="nextVideoTitle">Volgende video</string>
|
||||
<string name="showNextVideoTitle">\"Volgende video\" weergeven</string>
|
||||
<string name="urlNotSupportedText">URL wordt niet ondersteund.</string>
|
||||
<string name="showSimilarVideosButtonText">Vergelijkbare videos</string>
|
||||
<string name="showNextAndSimilarTitle">Laat volgende en vergelijkbare videos zien</string>
|
||||
</resources>
|
||||
|
||||
54
app/src/main/res/values-ru/strings.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">Ничего не найдено</string>
|
||||
<string name="viewSufix">просмотров</string>
|
||||
<string name="uploadDatePrefix">Опубликовано: </string>
|
||||
<string name="noPlayerFound">Ни одного потокового проигрывателя не было найдено. Установить?</string>
|
||||
<string name="installStreamPlayer">Установить</string>
|
||||
<string name="cancel">Отмена</string>
|
||||
<string name="fdroidVLCurl">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
|
||||
<string name="open_in_browser">Открыть в браузере</string>
|
||||
<string name="share">Поделиться</string>
|
||||
<string name="play">Воспроизвести</string>
|
||||
<string name="download">Скачать</string>
|
||||
<string name="search">Найти</string>
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="sendWith">Отправить с помощью</string>
|
||||
<string name="didYouMean">Возможно, вы имели в виду: </string>
|
||||
<string name="searchPage">Страница поиска: </string>
|
||||
<string name="shareDialogTitle">Поделиться с помощью:</string>
|
||||
<string name="chooseBrowser">Выбрать браузер:</string>
|
||||
<string name="screenRotation">поворот</string>
|
||||
<string name="title_activity_settings">Настройки</string>
|
||||
<string name="useExternalPlayerTitle">Использовать внешний проигрыватель</string>
|
||||
<string name="downloadLocation">Место для загрузок</string>
|
||||
<string name="downloadLocationSummary">Папка для хранения загруженных файлов.</string>
|
||||
<string name="downloadLocationDialogTitle">Введите путь к папке для загрузок</string>
|
||||
<string name="autoPlayThroughIntentTitle">Автопроигрывание через интернет</string>
|
||||
<string name="autoPlayThroughIntentSummary">Автоматически воспроизводить видео когда оно открыто через другое приложение.</string>
|
||||
<string name="defaultResolutionPreferenceTitle">Разрешение по-умолчанию</string>
|
||||
<string name="playWithKodiTitle">Воспроизвести с помощью Kodi</string>
|
||||
<string name="koreNotFound">Приложение Kore не наидено. Чтобы проигрывать видео через Kodi media center, нужен Kore.</string>
|
||||
<string name="installeKore">Установить Kore</string>
|
||||
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore</string>
|
||||
<string name="showPlayWithKodiTitle">Показывать опцию \"Воспроизвести с помощью Kodi\"</string>
|
||||
<string name="showPlayWithKodiSummary">Показать опцию воспроизведения видео через Kodi media center.</string>
|
||||
<string name="leftPlayButtonTitle">Показать кнопку воспроизведения слева.</string>
|
||||
<string name="playAudio">Аудио</string>
|
||||
<string name="defaultAudioFormatTitle">Формат аудио по-умолчанию</string>
|
||||
<string name="webMAudioDescription">WebM - свободный формат</string>
|
||||
<string name="m4aAudioDescription">m4a - лучшее качество</string>
|
||||
<string name="downloadDialogTitle">Скачать</string>
|
||||
<string-array name="downloadOptions">
|
||||
<item>Видео</item>
|
||||
<item>Аудио</item>
|
||||
</string-array>
|
||||
<string name="nextVideoTitle">Следующее видео</string>
|
||||
<string name="showNextVideoTitle">Показать \"Следующее видео\".</string>
|
||||
<string name="urlNotSupportedText">URL не поддерживается.</string>
|
||||
<string name="showSimilarVideosButtonText">Похожие видео</string>
|
||||
<string name="showNextAndSimilarTitle">Показывать следующее и предложенные видео</string>
|
||||
<string name="searchLanguageTitle">Предпочитаемый язык контента</string>
|
||||
</resources>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">Јутјуб цев</string>
|
||||
<string name="title_videoitem_detail">Јутјуб цев</string>
|
||||
@@ -29,4 +29,23 @@
|
||||
<string name="autoPlayThroughIntentTitle">Аутопуштање преко Интента</string>
|
||||
<string name="autoPlayThroughIntentSummary">Аутоматски почиње пушта видео по позиву из друге апликације.</string>
|
||||
<string name="defaultResolutionPreferenceTitle">Подразумевана резолуција</string>
|
||||
<string name="playWithKodiTitle">Пусти помоћу Кодија</string>
|
||||
<string name="koreNotFound">Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру.</string>
|
||||
<string name="installeKore">Инсталирај Кор</string>
|
||||
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore</string>
|
||||
<string name="showPlayWithKodiTitle">Прикажи „Пусти помоћу Кодија“</string>
|
||||
<string name="showPlayWithKodiSummary">Приказ опције за пуштање видеа у Коди медија центру.</string>
|
||||
<string name="leftPlayButtonTitle">Прикажи дугме за пуштање на левој страни.</string>
|
||||
<string name="playAudio">Аудио</string>
|
||||
<string name="defaultAudioFormatTitle">Подразумевани формат звука</string>
|
||||
<string name="webMAudioDescription">WebM - слободни формат</string>
|
||||
<string name="m4aAudioDescription">m4a - бољи квалитет</string>
|
||||
<string name="downloadDialogTitle">Преузми</string>
|
||||
<string-array name="downloadOptions">
|
||||
<item>Видео</item>
|
||||
<item>Аудио</item>
|
||||
</string-array>
|
||||
<string name="nextVideoTitle">Следећи видео</string>
|
||||
<string name="showNextVideoTitle">Приказ ставке „Следећи видео“.</string>
|
||||
<string name="urlNotSupportedText">УРЛ није подржан.</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="primaryColorYoutube">#dd0000</color>
|
||||
<color name="primaryColorDarkYoutube">#bb0000</color>
|
||||
<color name="primaryColorYoutube">#cd322e</color>
|
||||
<color name="primaryColorDarkYoutube">#bc211d</color>
|
||||
<color name="accentColorYoutube">#000000</color>
|
||||
<color name="black_overlay">#66000000</color>
|
||||
</resources>
|
||||
@@ -4,4 +4,10 @@
|
||||
<dimen name="text_search_duration_size">11sp</dimen>
|
||||
<dimen name="text_search_uploader_size">12sp</dimen>
|
||||
<dimen name="text_search_uploadtime_size">12sp</dimen>
|
||||
<dimen name="text_video_title_size">14sp</dimen>
|
||||
<dimen name="text_video_visits_size">14sp</dimen>
|
||||
<dimen name="text_video_like_size">12sp</dimen>
|
||||
<dimen name="text_video_uploader_size">14sp</dimen>
|
||||
<dimen name="text_video_uploadtime_size">14sp</dimen>
|
||||
<dimen name="text_video_description_size">14sp</dimen>
|
||||
</resources>
|
||||
@@ -23,4 +23,164 @@
|
||||
<item>m4a</item>
|
||||
</string-array>
|
||||
<string name="defaultAudioFormat">m4a</string>
|
||||
<string name="showNextVideo">show_next_video</string>
|
||||
<string name="searchLanguage">search_language</string>
|
||||
<!-- TODO: scrape these programmatically, then store in a local cache -->
|
||||
<!-- alternatively, load these from some local android data store -->
|
||||
<string-array name='languageCodes'>
|
||||
<item>af</item>
|
||||
<item>az</item>
|
||||
<item>id</item>
|
||||
<item>ms</item>
|
||||
<item>ca</item>
|
||||
<item>cs</item>
|
||||
<item>da</item>
|
||||
<item>de</item>
|
||||
<item>et</item>
|
||||
<item>en-GB</item>
|
||||
<item>en</item>
|
||||
<item>es</item>
|
||||
<item>es-419</item>
|
||||
<item>eu</item>
|
||||
<item>fil</item>
|
||||
<item>fr</item>
|
||||
<item>fr-CA</item>
|
||||
<item>gl</item>
|
||||
<item>hr</item>
|
||||
<item>zu</item>
|
||||
<item>is</item>
|
||||
<item>it</item>
|
||||
<item>sw</item>
|
||||
<item>lv</item>
|
||||
<item>lt</item>
|
||||
<item>hu</item>
|
||||
<item>nl</item>
|
||||
<item>no</item>
|
||||
<item>uz</item>
|
||||
<item>pl</item>
|
||||
<item>pt-PT</item>
|
||||
<item>pt</item>
|
||||
<item>ro</item>
|
||||
<item>sq</item>
|
||||
<item>sk</item>
|
||||
<item>sl</item>
|
||||
<item>fi</item>
|
||||
<item>sv</item>
|
||||
<item>vi</item>
|
||||
<item>tr</item>
|
||||
<item>bg</item>
|
||||
<item>ky</item>
|
||||
<item>kk</item>
|
||||
<item>mk</item>
|
||||
<item>mn</item>
|
||||
<item>ru</item>
|
||||
<item>sr</item>
|
||||
<item>uk</item>
|
||||
<item>el</item>
|
||||
<item>hy</item>
|
||||
<item>iw</item>
|
||||
<item>ur</item>
|
||||
<item>ar</item>
|
||||
<item>fa</item>
|
||||
<item>ne</item>
|
||||
<item>mr</item>
|
||||
<item>hi</item>
|
||||
<item>bn</item>
|
||||
<item>pa</item>
|
||||
<item>gu</item>
|
||||
<item>ta</item>
|
||||
<item>te</item>
|
||||
<item>kn</item>
|
||||
<item>ml</item>
|
||||
<item>si</item>
|
||||
<item>th</item>
|
||||
<item>lo</item>
|
||||
<item>my</item>
|
||||
<item>ka</item>
|
||||
<item>am</item>
|
||||
<item>km</item>
|
||||
<item>zh-CN</item>
|
||||
<item>zh-TW</item>
|
||||
<item>zh-HK</item>
|
||||
<item>ja</item>
|
||||
<item>ko</item>
|
||||
</string-array>
|
||||
<string-array name='languageNames'>
|
||||
<item>Afrikaans</item>
|
||||
<item>Azərbaycan</item>
|
||||
<item>Bahasa Indonesia</item>
|
||||
<item>Bahasa Malaysia</item>
|
||||
<item>Català</item>
|
||||
<item>Čeština</item>
|
||||
<item>Dansk</item>
|
||||
<item>Deutsch</item>
|
||||
<item>Eesti</item>
|
||||
<item>English (UK)</item>
|
||||
<item>English (US)</item>
|
||||
<item>Español (España)</item>
|
||||
<item>Español (Latinoamérica)</item>
|
||||
<item>Euskara</item>
|
||||
<item>Filipino</item>
|
||||
<item>Français</item>
|
||||
<item>Français (Canada)</item>
|
||||
<item>Galego</item>
|
||||
<item>Hrvatski</item>
|
||||
<item>IsiZulu</item>
|
||||
<item>Íslenska</item>
|
||||
<item>Italiano</item>
|
||||
<item>Kiswahili</item>
|
||||
<item>Latviešu valoda</item>
|
||||
<item>Lietuvių</item>
|
||||
<item>Magyar</item>
|
||||
<item>Nederlands</item>
|
||||
<item>Norsk</item>
|
||||
<item>O‘zbek</item>
|
||||
<item>Polski</item>
|
||||
<item>Português</item>
|
||||
<item>Português (Brasil)</item>
|
||||
<item>Română</item>
|
||||
<item>Shqip</item>
|
||||
<item>Slovenčina</item>
|
||||
<item>Slovenščina</item>
|
||||
<item>Suomi</item>
|
||||
<item>Svenska</item>
|
||||
<item>Tiếng Việt</item>
|
||||
<item>Türkçe</item>
|
||||
<item>Български</item>
|
||||
<item>Кыргызча</item>
|
||||
<item>Қазақ Тілі</item>
|
||||
<item>Македонски</item>
|
||||
<item>Монгол</item>
|
||||
<item>Русский</item>
|
||||
<item>Српски</item>
|
||||
<item>Українська</item>
|
||||
<item>Ελληνικά</item>
|
||||
<item>Հայերեն</item>
|
||||
<item>עברית</item>
|
||||
<item>اردو</item>
|
||||
<item>العربية</item>
|
||||
<item>فارسی</item>
|
||||
<item>नेपाली</item>
|
||||
<item>मराठी</item>
|
||||
<item>हिन्दी</item>
|
||||
<item>বাংলা</item>
|
||||
<item>ਪੰਜਾਬੀ</item>
|
||||
<item>ગુજરાતી</item>
|
||||
<item>தமிழ்</item>
|
||||
<item>తెలుగు</item>
|
||||
<item>ಕನ್ನಡ</item>
|
||||
<item>മലയാളം</item>
|
||||
<item>සිංහල</item>
|
||||
<item>ภาษาไทย</item>
|
||||
<item>ລາວ</item>
|
||||
<item>ဗမာ</item>
|
||||
<item>ქართული</item>
|
||||
<item>አማርኛ</item>
|
||||
<item>ខ្មែរ</item>
|
||||
<item>中文 (简体)</item>
|
||||
<item>中文 (繁體)</item>
|
||||
<item>中文 (香港)</item>
|
||||
<item>日本語</item>
|
||||
<item>한국어</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">NewPipe</string>
|
||||
<string name="title_videoitem_detail">NewPipe</string>
|
||||
<string name="nothingFound">Nothing found</string>
|
||||
<string name="viewSufix">views</string>
|
||||
<string name="uploadDatePrefix">Uploaded at: </string>
|
||||
<string name="noPlayerFound">No StreamPlayer found. You may want to install one.</string>
|
||||
<string name="installStreamPlayer">Install one</string>
|
||||
<string name="uploadDatePrefix">Uploaded on </string>
|
||||
<string name="noPlayerFound">No stream player found. You may want to install one.</string>
|
||||
<string name="installStreamPlayer">Install</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="fdroidVLCurl">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string>
|
||||
<string name="open_in_browser">Open in browser</string>
|
||||
@@ -45,4 +45,9 @@
|
||||
<item>Video</item>
|
||||
<item>Audio</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
<string name="nextVideoTitle">Next video</string>
|
||||
<string name="showNextAndSimilarTitle">Show next and similar videos</string>
|
||||
<string name="urlNotSupportedText">URL not supported.</string>
|
||||
<string name="showSimilarVideosButtonText">Similar videos</string>
|
||||
<string name="searchLanguageTitle">Preferable content language</string>
|
||||
</resources>
|
||||
|
||||
@@ -46,4 +46,16 @@
|
||||
android:entryValues="@array/audioFormatList"
|
||||
android:defaultValue="@string/defaultAudioFormat"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="@string/showNextVideo"
|
||||
android:title="@string/showNextAndSimilarTitle"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<ListPreference
|
||||
android:key="@string/searchLanguage"
|
||||
android:title="@string/searchLanguageTitle"
|
||||
android:entries="@array/languageNames"
|
||||
android:entryValues="@array/languageCodes"
|
||||
android:defaultValue="en" />
|
||||
|
||||
</PreferenceScreen>
|
||||
394
assets/new_pipe_icon_3.svg
Normal file
@@ -0,0 +1,394 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
viewBox="0 0 192 192"
|
||||
height="192"
|
||||
width="192"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="new_pipe_icon_3.svg"
|
||||
inkscape:export-filename="/home/the-scrabi/Projects/NewPipe/app/src/main/res/mipmap-xxhdpi/ic_launcher.png"
|
||||
inkscape:export-xdpi="67.5"
|
||||
inkscape:export-ydpi="67.5">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
id="namedview4149"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.7234659"
|
||||
inkscape:cx="82.753124"
|
||||
inkscape:cy="90.951077"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4924">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.12857144"
|
||||
offset="0"
|
||||
id="stop4926" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop4928" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4454"
|
||||
width="1.4"
|
||||
height="1.4"
|
||||
x="-0.2"
|
||||
y="-0.2">
|
||||
<feFlood
|
||||
flood-opacity="0.427451"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4456" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4458" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="10.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4460" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="7"
|
||||
result="offset"
|
||||
id="feOffset4462" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4464" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4777">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4779" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4781" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="5.82011"
|
||||
result="blur"
|
||||
id="feGaussianBlur4783" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5.6"
|
||||
result="offset"
|
||||
id="feOffset4785" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4787" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4789" />
|
||||
<feFlood
|
||||
id="feFlood4791"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4793"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4795"
|
||||
in="composite1"
|
||||
stdDeviation="5.8"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4797"
|
||||
dx="0"
|
||||
dy="5.6"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4799"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4885">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4887" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4889" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4891" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2.54709"
|
||||
result="offset"
|
||||
id="feOffset4893" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4895" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4897" />
|
||||
<feFlood
|
||||
id="feFlood4899"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4901"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4903"
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4905"
|
||||
dx="0"
|
||||
dy="2.5"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4907"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4924"
|
||||
id="radialGradient4930"
|
||||
cx="-17.308468"
|
||||
cy="44.131577"
|
||||
fx="-17.308468"
|
||||
fy="44.131577"
|
||||
r="88"
|
||||
gradientTransform="matrix(0.00918061,2.1580507,-2.1734097,0.00924596,96.458612,37.749457)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4257">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4259" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4261" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4263" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5.02645"
|
||||
result="offset"
|
||||
id="feOffset4265" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4267" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4269" />
|
||||
<feFlood
|
||||
id="feFlood4271"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4273"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4275"
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4277"
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4279"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4192">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4194" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4196" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.7"
|
||||
result="blur"
|
||||
id="feGaussianBlur4198" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset"
|
||||
id="feOffset4200" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4202" />
|
||||
</filter>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="g4191"
|
||||
transform="matrix(1.0909091,0,0,1.0909091,-8.7272727,-8.6363651)">
|
||||
<rect
|
||||
ry="20.886885"
|
||||
y="31"
|
||||
x="8"
|
||||
height="128"
|
||||
width="176"
|
||||
id="rect4138-6"
|
||||
style="fill:#747474;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
ry="20.886885"
|
||||
y="33"
|
||||
x="8"
|
||||
height="128"
|
||||
width="176"
|
||||
id="rect4138-9"
|
||||
style="fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
ry="20.886885"
|
||||
y="32"
|
||||
x="8"
|
||||
height="128"
|
||||
width="176"
|
||||
id="rect4138"
|
||||
style="fill:#616161;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<g
|
||||
style="filter:url(#filter4192)"
|
||||
transform="matrix(0.57861531,0,0,0.57861531,-50.721139,-52.115781)"
|
||||
id="g4141">
|
||||
<circle
|
||||
style="fill:#ff5252;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144"
|
||||
cx="255.30112"
|
||||
cy="257.71143"
|
||||
r="86.413193" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4140"
|
||||
d="m 303.94425,257.77663 -40.45827,23.31512 -40.45827,23.31511 0.0377,-46.69544 0.0377,-46.69545 40.42062,23.38033 z" />
|
||||
</g>
|
||||
<rect
|
||||
ry="21.213242"
|
||||
y="31"
|
||||
x="8"
|
||||
height="130"
|
||||
width="176"
|
||||
id="rect4138-8"
|
||||
style="fill:url(#radialGradient4930);fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
526
assets/new_pipe_icon_4.svg
Normal file
@@ -0,0 +1,526 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
viewBox="0 0 192 192"
|
||||
height="192"
|
||||
width="192"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="new_pipe_icon_4.svg"
|
||||
inkscape:export-filename="/home/the-scrabi/Projects/NewPipe/app/src/main/res/mipmap-xxhdpi/ic_launcher.png"
|
||||
inkscape:export-xdpi="67.5"
|
||||
inkscape:export-ydpi="67.5">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
id="namedview4149"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.2793069"
|
||||
inkscape:cx="74.912287"
|
||||
inkscape:cy="82.673449"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4447">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.1"
|
||||
offset="0"
|
||||
id="stop4449" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop4451" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4454"
|
||||
width="1.4"
|
||||
height="1.4"
|
||||
x="-0.2"
|
||||
y="-0.2">
|
||||
<feFlood
|
||||
flood-opacity="0.427451"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4456" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4458" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="10.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4460" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="7"
|
||||
result="offset"
|
||||
id="feOffset4462" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4464" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4777">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4779" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4781" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="5.82011"
|
||||
result="blur"
|
||||
id="feGaussianBlur4783" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5.6"
|
||||
result="offset"
|
||||
id="feOffset4785" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4787" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4789" />
|
||||
<feFlood
|
||||
id="feFlood4791"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4793"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4795"
|
||||
in="composite1"
|
||||
stdDeviation="5.8"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4797"
|
||||
dx="0"
|
||||
dy="5.6"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4799"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4885">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4887" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4889" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4891" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2.54709"
|
||||
result="offset"
|
||||
id="feOffset4893" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4895" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4897" />
|
||||
<feFlood
|
||||
id="feFlood4899"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4901"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4903"
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4905"
|
||||
dx="0"
|
||||
dy="2.5"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4907"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4257">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4259" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4261" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur"
|
||||
id="feGaussianBlur4263" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5.02645"
|
||||
result="offset"
|
||||
id="feOffset4265" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="fbSourceGraphic"
|
||||
id="feComposite4267" />
|
||||
<feColorMatrix
|
||||
result="fbSourceGraphicAlpha"
|
||||
in="fbSourceGraphic"
|
||||
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
|
||||
id="feColorMatrix4269" />
|
||||
<feFlood
|
||||
id="feFlood4271"
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
in="fbSourceGraphic" />
|
||||
<feComposite
|
||||
id="feComposite4273"
|
||||
in2="fbSourceGraphic"
|
||||
in="flood"
|
||||
operator="in"
|
||||
result="composite1" />
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur4275"
|
||||
in="composite1"
|
||||
stdDeviation="7.9"
|
||||
result="blur" />
|
||||
<feOffset
|
||||
id="feOffset4277"
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset" />
|
||||
<feComposite
|
||||
id="feComposite4279"
|
||||
in2="offset"
|
||||
in="fbSourceGraphic"
|
||||
operator="over"
|
||||
result="composite2" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4192">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4194" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4196" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.7"
|
||||
result="blur"
|
||||
id="feGaussianBlur4198" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset"
|
||||
id="feOffset4200" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4202" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4349">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4351" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4353" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="7.2"
|
||||
result="blur"
|
||||
id="feGaussianBlur4355" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset"
|
||||
id="feOffset4357" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4359" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4361">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4363" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4365" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="5.3"
|
||||
result="blur"
|
||||
id="feGaussianBlur4367" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset"
|
||||
id="feOffset4369" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4371" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4481">
|
||||
<feFlood
|
||||
flood-opacity="0.498039"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4483" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4485" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="5"
|
||||
result="blur"
|
||||
id="feGaussianBlur4487" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="5"
|
||||
result="offset"
|
||||
id="feOffset4489" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4491" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter4433">
|
||||
<feFlood
|
||||
flood-opacity="0.2"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood4435" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite4437" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="4"
|
||||
result="blur"
|
||||
id="feGaussianBlur4439" />
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="4"
|
||||
result="offset"
|
||||
id="feOffset4441" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite4443" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4447"
|
||||
id="radialGradient4453"
|
||||
cx="0.56012386"
|
||||
cy="0.35701406"
|
||||
fx="0.56012386"
|
||||
fy="0.35701406"
|
||||
r="88"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.00132321,2.1587518,-2.1815784,0.00133718,1.1350038,-0.41402508)" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
style="opacity:1;fill:#ff7575;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144-9"
|
||||
r="88"
|
||||
cy="104"
|
||||
cx="88" />
|
||||
<circle
|
||||
style="fill:#ff5252;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144-6"
|
||||
cx="88"
|
||||
cy="104"
|
||||
r="0" />
|
||||
<g
|
||||
id="g4455">
|
||||
<g
|
||||
style="filter:url(#filter4433)"
|
||||
transform="translate(8,-8)"
|
||||
id="g4416">
|
||||
<circle
|
||||
style="opacity:1;fill:#ff7575;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144-67"
|
||||
cx="88"
|
||||
cy="104"
|
||||
r="88" />
|
||||
<path
|
||||
style="opacity:1;fill:#cc4242;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144-5"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="88"
|
||||
sodipodi:cy="104"
|
||||
sodipodi:rx="88"
|
||||
sodipodi:ry="88"
|
||||
sodipodi:start="0"
|
||||
sodipodi:end="3.1387981"
|
||||
sodipodi:open="true"
|
||||
d="M 176,104 A 88,88 0 0 1 88.12296,191.99991 88,88 0 0 1 3.4361909e-4,104.24592" />
|
||||
<ellipse
|
||||
style="fill:#ff5252;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4144"
|
||||
cx="88"
|
||||
cy="104"
|
||||
rx="88"
|
||||
ry="87" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:17.10300064;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4140"
|
||||
d="M 137.53637,104.0664 96.33516,127.80966 55.133958,151.5529 55.17235,104 55.210742,56.447076 96.37361,80.256739 Z" />
|
||||
</g>
|
||||
<circle
|
||||
r="88"
|
||||
cy="96"
|
||||
cx="96"
|
||||
id="path4445"
|
||||
style="opacity:1;fill:url(#radialGradient4453);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |