1
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-09-21 22:20:50 +02:00

Compare commits

...

90 Commits

Author SHA1 Message Date
Adam Howard
c4ea73ca7a Merge pull request #93 from chschtsch/patch-6
remove quotation marks added by weblate
2015-11-13 12:19:21 +00:00
Adam Howard
2aa28d6453 Merge pull request #92 from chschtsch/patch-5
remove quotation marks added by weblate
2015-11-13 12:19:11 +00:00
Adam Howard
2d51085ccf Merge pull request #91 from chschtsch/patch-4
remove quotation marks added by weblate
2015-11-13 12:19:03 +00:00
Adam Howard
4eae02e47e Merge pull request #90 from chschtsch/patch-2
remove quotation marks added by weblate
2015-11-13 12:18:48 +00:00
Adam Howard
f3bf9f9e5d Merge pull request #89 from chschtsch/patch-3
remove quotation marks added by weblate
2015-11-13 12:18:38 +00:00
Greg
75d0b84bdb remove quotation marks added by weblate 2015-11-13 15:00:24 +03:00
Greg
3643ddcf5c remove quotation marks added by weblate 2015-11-13 14:58:16 +03:00
Greg
35500e8ef7 remove quotation marks added by weblate 2015-11-13 14:57:52 +03:00
Greg
6badcf5391 remove quotation marks added by weblate 2015-11-13 14:57:09 +03:00
Greg
d4898043f6 remove quotation marks added by weblate 2015-11-13 14:56:38 +03:00
Weblate
2322ba833a Merge remote-tracking branch 'origin/master' 2015-11-13 12:27:21 +01:00
Greg
5aabb2917f Translated using Weblate (Spanish)
Currently translated at 95.6% (44 of 46 strings)
2015-11-13 12:27:21 +01:00
Greg
eacbf6ce50 Translated using Weblate (German)
Currently translated at 97.8% (45 of 46 strings)
2015-11-13 12:27:20 +01:00
Greg
031300a132 Translated using Weblate (French)
Currently translated at 76.0% (35 of 46 strings)
2015-11-13 12:27:20 +01:00
Greg
f905611e69 Translated using Weblate (English)
Currently translated at 100.0% (46 of 46 strings)

changing 'published' to 'updloaded'
2015-11-13 12:27:20 +01:00
Greg
e475f9f876 Translated using Weblate (Dutch)
Currently translated at 97.8% (45 of 46 strings)
2015-11-13 12:27:20 +01:00
Adam Howard
b65263349e Merged upstream translation commits 2015-11-13 11:07:22 +00:00
Adam Howard
5cb8026f6d Merge pull request #87 from chschtsch/patch-1
remove quotation marks added by weblate
2015-11-13 11:05:48 +00:00
Adam Howard
cc7ce5cf93 fixed inefficient double-conversion of parceled VideoInfoItems, from being cast from VideoInfoItem[] to Vector<>, to using ArrayList as an implementation of List 2015-11-13 10:47:05 +00:00
Greg
af506639a9 remove quotation marks added by weblate 2015-11-13 12:46:55 +03:00
Greg
d377d67174 Translated using Weblate (Russian)
Currently translated at 100.0% (46 of 46 strings)
2015-11-13 10:06:06 +01:00
Greg
cf926353d1 Translated using Weblate (Russian)
Currently translated at 100.0% (46 of 46 strings)
2015-11-13 09:54:54 +01:00
Weblate
d686c744d0 Merge remote-tracking branch 'origin/master' 2015-11-13 03:22:52 +01:00
Greg
501c60b180 Translated using Weblate (Russian)
Currently translated at 97.8% (45 of 46 strings)
2015-11-13 03:22:52 +01:00
jasperweiss
da36687e25 Translated using Weblate (Dutch)
Currently translated at 100.0% (46 of 46 strings)
2015-11-13 03:22:52 +01:00
Adam Howard
f13f9a066a updated README to include language-specific search feature 2015-11-12 15:51:22 +00:00
Christian Schabesberger
8eaa4f7654 Merge pull request #82 from chschtsch/master
fix bug with parsing like/dislike count
2015-11-12 10:26:50 +01:00
Greg
145a7f8e0d fix bug with parsing like/dislike count 2015-11-12 12:18:41 +03:00
Adam Howard
67ba126602 implemented locale-specific formatting of view, like and dislike counts, and video published date 2015-11-11 16:23:22 +00:00
Adam Howard
c5084901b5 removed commented-out code, added another TODO note 2015-11-11 13:08:53 +00:00
Adam Howard
3bfc82f7c0 Refactoring YoutubeExtractor:
-replaced single use of terrible_unescape_workaround_fuck(String) with call to URLDecoder.decode(String, String)
* tested new regex implementation of YoutubeExtractor.getVideoId(String)
- deleted old HashMap-based implementation of YoutubeExtractor.getVideoId(String)
* Miscellaneous typo corrections
* replaced direct page-scraping extraction of video publication date in YoutubeExtractor.getVideoInfo(String) with jsoup-based scrape of <meta> tag field in YYYY-MM-DD format
*similarly,  replaced direct page-scraping extraction of view count with <meta> tag field.

Both <meta> tag fields still need to be formatted locale-specifically
2015-11-11 13:07:09 +00:00
Adam Howard
3411b53450 implemented optimised version of YoutubeExtractor.getVideoId().
new version uses a regular expression instead of creating a HashMap and looping over them.
Needs testing before pushing to origin
2015-11-11 01:48:44 +00:00
Christian Schabesberger
873564f2aa removed .idea folder 2015-11-10 21:17:07 +01:00
Christian Schabesberger
353ed90d12 New version number 0.6.0 and some fixes:
* moved on to version 0.6.0
* fixed youtube url sicnature encryption (vevo videos can be watched again)
* removed play action from the ActionBar
* rolled back changes for hiding the InfoBar inside PlayVideoActivity
* some small layout changes
* removed some files to be ignored (mostly inside .idea directory)
* etc
2015-11-10 20:51:39 +01:00
Christian Schabesberger
799faecc5b Merge pull request #80 from chschtsch/master
Update layout (initially suggested by @darkon5) + miscellaneous fixes
2015-11-10 19:28:53 +01:00
chschtsch
731321b1f9 tryna merge dem files 2015-11-10 20:50:15 +03:00
chschtsch
7ff43caf96 tryna merge dem files 2015-11-10 20:36:35 +03:00
chschtsch
d0877c3132 tryna merge dem files 2015-11-10 20:34:08 +03:00
chschtsch
c589b03dcb rollback setting English as a default language for content 2015-11-10 20:28:05 +03:00
chschtsch
862b5aaef6 update layout (implementing redesign suggested by @darkon5) & set english as a default language for content 2015-11-10 20:26:20 +03:00
Adam Howard
596443bf5e added licensing notice to MediaFormat 2015-11-10 17:23:07 +00:00
Adam Howard
27b450f1e3 minor commit:
-removed now-redundant language code check
2015-11-10 17:09:26 +00:00
chschtsch
61a09e97ca update colors (implementing redesign suggested by @darkon5) 2015-11-10 19:55:58 +03:00
chschtsch
224e7a8969 update date extracting regex pattern + fix some strings in English 2015-11-10 19:50:04 +03:00
Adam Howard
9e7d9ee973 merged commits from origin 2015-11-10 12:43:40 +00:00
Weblate
586bad345c Merge remote-tracking branch 'origin/master' 2015-11-09 08:16:47 +01:00
Szöllősi Attila
abdd7dc7d3 Translated using Weblate (Hungarian)
Currently translated at 97.8% (45 of 46 strings)
2015-11-09 08:16:47 +01:00
jasperweiss
aee32f7a3e Translated using Weblate (Dutch)
Currently translated at 100.0% (46 of 46 strings)
2015-11-09 08:16:45 +01:00
Christian Schabesberger
696760e65a removed printing the player url 2015-11-08 21:22:24 +01:00
Christian Schabesberger
200db15d4b Merge branch 'master' of github.com:theScrabi/NewPipe 2015-11-08 21:19:09 +01:00
Christian Schabesberger
33e332f105 impofed performance and made similar video button hidable 2015-11-08 21:17:51 +01:00
Timofonic
bb2955e442 Translated using Weblate (Spanish)
Currently translated at 100.0% (46 of 46 strings)
2015-11-08 19:54:28 +01:00
Adam Howard
2fc2fa56c3 refactoring VideoInfo & MediaFormat, part 2:
* fixed errors caused by moving media format code to MediaFormat enum
2015-11-08 02:22:40 +00:00
Adam Howard
c87458590c refactoring VideoInfo & VideoInfoItem, part 1:
+ created enum VideoFormat
2015-11-08 02:04:03 +00:00
Adam Howard
8aff134c56 replaced content tountry selection with search language selection.Should now allows users to search for videos in their preferred language. Needs testing before pushing to origin. 2015-11-08 01:09:03 +00:00
Christian Schabesberger
4a938b81df Merge pull request #73 from joshsoftware/feature_search_suggestion
Feature search suggestion (enhancement)
2015-11-05 12:36:43 +01:00
chandrashekhar
4def715b25 + Added TODO & remove unused lines. 2015-11-05 13:19:28 +05:30
chandrashekhar
821acf12d8 +Merge Adam Howard's (medavox) commit with my changes & remove conflict.
+update searchEngine.java & YoutubeSearchEngine.java file.

Conflicts:
	app/src/main/java/org/schabi/newpipe/SearchEngine.java
	app/src/main/java/org/schabi/newpipe/youtube/YoutubeSearchEngine.java
2015-11-05 13:03:47 +05:30
Adam Howard
fc707b6c7e Added Content Country selection setting. This changes the SearchEngine interface slightly. Still need a reliable test to prove whether YouTube is serving different search results based on the country code passed in the search query. 2015-11-04 12:42:17 +00:00
chandrashekhar
85ac000479 + Change return type of interface method suggestionList, So that it will return arraylist of string type data(suggestion). 2015-11-04 11:44:34 +05:30
chandrashekhar
68a0eefa20 + Added interface method in SearchEngine class for fetch search suggestion list.
+ Implemented SearchEngine Interface method in YoutubeSearchEngine class.
2015-11-04 09:06:21 +05:30
Adam Howard
fc32377ce7 added check and exception reporting to YoutubeExtractor:matchGroup1, so that a failed match doesn't go unnoticed 2015-11-04 00:29:30 +00:00
Christian Schabesberger
59e512a64d fixed notification hiding issue 2015-11-03 22:19:28 +01:00
Christian Schabesberger
c51a5a51f1 Merge pull request #72 from medavox/master
Code cleanup & minor additions
2015-11-03 17:54:09 +01:00
Adam Howard
9546a276dc modified gitignore so jdk versions changes are hopefully not propagated to remote 2015-11-03 13:20:15 +00:00
Adam Howard
a18353df5f still fighting with jdk version strings in app/app.iml, .idea/gradle.xml, .idea/misc.xml 2015-11-03 13:19:23 +00:00
Adam Howard
3c72113f4c replaced 4-line regex blocks with call to equivalent method; removed unecessary try-catch blocks surrounding them: regex methods don't throw runtime exceptions 2015-11-03 12:56:11 +00:00
Adam Howard
7e193751c4 fixed app/app.iml, .idea/grade.xml and .idea/misc.xml siwtching jdk versions between 1.7 and 1.8. Added them to my local .gitignore 2015-11-03 12:08:30 +00:00
Adam Howard
56c96eb712 Merge remote-tracking branch 'upstream/master':
Synced new russian translation from theScrabi/NewPipe
2015-11-03 11:51:40 +00:00
Adam Howard
4106a984ca minor corrections pre-sync 2015-11-03 11:51:18 +00:00
Christian Schabesberger
10f1ab0598 Merge pull request #71 from chschtsch/patch-1
Add russian translation of strings.xml
2015-11-03 11:28:27 +01:00
chschtsch
bca9603440 Add russian translation of strings.xml 2015-11-03 12:34:51 +03:00
Adam Howard
c32c267889 Merge remote-tracking branch 'upstream/master'
Conflicts:
	app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java -- still used class-based passing
	app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java -- just some whitespace
2015-11-02 21:29:43 +00:00
Adam Howard
627e987bda made the PlayVideoActivity return to its VideoItemDetailActivity when the back button is pressed, by setting its parent activity in the manifest. Also grammar fixes for existing comments 2015-11-02 21:19:18 +00:00
Christian Schabesberger
7c18e147f3 added "show next/related videos" to features 2015-11-02 20:32:13 +01:00
Christian Schabesberger
6a8fb5910d changed icon in the README file 2015-11-02 20:18:23 +01:00
Christian Schabesberger
b865326d51 added ability to show similar videos 2015-11-02 19:57:47 +01:00
Adam Howard
a2d5b0893d Merge remote-tracking branch 'upstream/master' 2015-11-02 15:12:34 +00:00
Adam Howard
db0508b9ab refactored StreamingService interface so it acts as a Factory (returning new instances of called classes, eg Extractor), rather than passing Class objects (which loses type safety) which are then instantiated. Also noticed there is a conflict between existing gradle setup and mine: misc.xml and app.iml have had their jvm version values switched from 1.8 to 1.7 2015-11-02 15:03:11 +00:00
Christian Schabesberger
1850dee93a Merge pull request #67 from joshsoftware/remove_deprecation
Remove Deprecated methods
2015-11-02 15:37:17 +01:00
Weblate
7b1eb8a6dc Merge remote-tracking branch 'origin/master' 2015-11-02 14:26:43 +01:00
chandrashekhar
95a9f2f5e3 + Remove deprecated method from app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java
onAttach(Activity activity) is replaced by onAttach(Context context)

+ Remove deprecated method from pp/src/main/java/org/schabi/newpipe/VideoListAdapter.java
context.getResource().getColor(resId) is replaced by ContextCompat.getColor(context,resId)
2015-11-02 18:02:32 +05:30
darkon5
ae7ed2d226 Merge pull request #65 from medavox/master
Minor README edits
2015-11-02 10:18:24 +01:00
Szöllősi Attila
20cf82bab1 Translated using Weblate (Hungarian)
Currently translated at 100.0% (44 of 44 strings)
2015-11-01 21:42:52 +01:00
Mladen Pejaković
5dcb1e26b5 Translated using Weblate (Serbian)
Currently translated at 100.0% (44 of 44 strings)
2015-10-31 19:56:57 +01:00
Christian Schabesberger
8076589180 Translated using Weblate (German)
Currently translated at 100.0% (44 of 44 strings)
2015-10-31 16:11:54 +01:00
Christian Schabesberger
edbd4003be Merge pull request #64 from mamins1376/master
add Persian translation
2015-10-31 13:53:26 +01:00
medavox
122b089bf0 minor grammar 2015-10-31 12:07:07 +00:00
medavox
a28d917990 fixed typo 2015-10-31 12:05:42 +00:00
Mohammad Amin Sameti
5b605a1100 add Persian translation 2015-10-31 02:30:08 +03:30
53 changed files with 1098 additions and 731 deletions

5
.gitignore vendored
View File

@@ -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
View File

@@ -1 +0,0 @@
NewPipe

22
.idea/compiler.xml generated
View File

@@ -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>

View File

@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

View File

@@ -1,3 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="the-scrabi" />
</component>

19
.idea/gradle.xml generated
View File

@@ -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
View File

@@ -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
View File

@@ -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>

View File

@@ -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
View File

@@ -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>

View File

@@ -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>

View File

@@ -2,14 +2,14 @@
[![Translation Status](https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg)](https://hosted.weblate.org/engage/NewPipe/)
[![NewPipe](https://f-droid.org/repo/icons/org.schabi.newpipe.4.png)](http://dasochan.nl/newpipe/)
NewPipe: A free lightweight Youtube fronted for Android.
[![NewPipe](https://f-droid.org/repo/icons/org.schabi.newpipe.5.png)](http://dasochan.nl/newpipe/)
NewPipe: A free lightweight Youtube frontend for Android.
[![F-Droid](https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png)](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.
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
@@ -21,10 +21,11 @@ NewPipe does not use any Google framework libraries, or the Youtube api. It only
* 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
* Shows Next/Related videos
* Improved Downloading
* Bookmarks
* View history
@@ -37,9 +38,9 @@ NewPipe does not use any Google framework libraries, or the Youtube api. It only
* ... and many more
### Multi service support
Generally NewPipe is designed to not only support YouTube, but many more streaming services. How ever, right now NewPipe is not stable enough to support more than only youtube. But if all works as plant, NewPipe will get such support by the version 2.0.
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 its about ideas, translation, design changes, code cleaning, or real heavy code changes. 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
View File

@@ -1 +1,3 @@
.gitignore
/build
app.iml

View File

@@ -1,103 +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.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.1.0/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="recyclerview-v7-23.1.0" level="project" />
<orderEntry type="library" exported="" name="jsoup-1.8.3" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.1.0" level="project" />
<orderEntry type="library" exported="" name="rhino-1.7.7" level="project" />
<orderEntry type="library" exported="" name="design-23.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.1.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.1.0" level="project" />
</component>
</module>

View File

@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 23
versionCode 5
versionName "0.5.0"
versionCode 6
versionName "0.6.0"
}
buildTypes {
release {
@@ -23,7 +23,7 @@ dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
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.1.0'
}

View File

@@ -68,6 +68,7 @@
<activity android:name=".PlayVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/FullscreenTheme"
android:parentActivityName=".VideoItemDetailActivity"
>
</activity>
<activity

View File

@@ -69,6 +69,7 @@ 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(activity.getString(R.string.defaultResolutionPreference),
@@ -76,7 +77,7 @@ public class ActionBarHandler {
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;
}
@@ -93,21 +94,19 @@ public class ActionBarHandler {
// set audioStream
audioStream = null;
String preferedFormat = PreferenceManager.getDefaultSharedPreferences(activity)
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 &&
if(s.format == MediaFormat.M4A.id &&
(audioStream == null || audioStream.bandwidth > s.bandwidth)) {
audioStream = s;
Log.d(TAG, "last choosen");
}
}
}
@@ -124,15 +123,8 @@ public class ActionBarHandler {
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(activity.getString(R.string.showPlayWidthKodiPreference), false));
@@ -142,9 +134,6 @@ public class ActionBarHandler {
public boolean onItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case R.id.menu_item_play:
playVideo();
return true;
case R.id.menu_item_share:
if(!videoTitle.isEmpty()) {
Intent intent = new Intent();
@@ -195,7 +184,7 @@ 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);
@@ -234,10 +223,9 @@ public class ActionBarHandler {
}
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);
@@ -296,7 +284,7 @@ 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);
activity.startActivity(intent); // HERE !!!
@@ -320,7 +308,7 @@ public class ActionBarHandler {
}
});
builder.create().show();
Log.d(TAG, "Either no Streaming player for audio was installed, or something importand crashed:");
Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
e.printStackTrace();
}
}

View File

@@ -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;
}
}

View 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 "";
}
}

View File

@@ -1,5 +1,6 @@
package org.schabi.newpipe;
import java.util.ArrayList;
import java.util.Vector;
/**
@@ -31,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);
}

View File

@@ -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);
}

View File

@@ -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) {
@@ -118,28 +75,5 @@ public class VideoInfo {
public int format = -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;
}

View File

@@ -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,14 +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];
}
};
}

View File

@@ -51,7 +51,7 @@ public class VideoInfoItemViewCreator {
}
if(info.thumbnail == null) {
holder.itemThumbnailView.setImageResource(R.drawable.dummi_thumbnail);
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
} else {
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
}
@@ -61,7 +61,7 @@ public class VideoInfoItemViewCreator {
if(!info.upload_date.isEmpty()) {
holder.itemUploadDateView.setText(info.upload_date);
} else {
//tewak if nececeary: This is a hack preventing to have a white space in the layout :P
//tweak if necessary: This is a hack to prevent having white space in the layout :P
holder.itemUploadDateView.setText(info.view_count);
}

View File

@@ -5,6 +5,7 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -37,7 +38,6 @@ public class VideoItemDetailActivity extends AppCompatActivity {
private String videoUrl;
private int currentStreamingService = -1;
private Menu menu = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -61,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++) {
@@ -68,8 +69,7 @@ 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();
}
@@ -123,9 +123,9 @@ 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);

View File

@@ -3,8 +3,12 @@ package org.schabi.newpipe;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -12,6 +16,9 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
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.
@@ -34,9 +41,19 @@ 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 = "";
@@ -87,17 +104,30 @@ 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()) {
@@ -120,15 +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());
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);
}
/**
@@ -178,7 +211,8 @@ public class VideoItemListActivity extends AppCompatActivity
super.onCreateOptionsMenu(menu);
this.menu = menu;
MenuInflater inflater = getMenuInflater();
if(findViewById(R.id.videoitem_detail_container) == null) {
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();
@@ -198,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 {
return videoFragment.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

View File

@@ -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,8 @@ import android.widget.ListView;
import android.widget.Toast;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
@@ -41,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;
@@ -50,6 +59,7 @@ 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;
@@ -65,14 +75,14 @@ public class VideoItemListFragment extends ListFragment {
}
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;
@@ -82,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));
}
@@ -161,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();
@@ -179,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();
}
@@ -203,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();
@@ -234,10 +251,6 @@ public class VideoItemListFragment extends ListFragment {
}
}
void displayList() {
}
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
@@ -271,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);
@@ -282,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
@@ -292,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();
@@ -308,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

View File

@@ -2,12 +2,14 @@ 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.ListView;
import java.util.List;
import java.util.Vector;
/**
@@ -47,7 +49,7 @@ public class VideoListAdapter extends BaseAdapter {
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);
@@ -99,7 +101,7 @@ public class VideoListAdapter extends BaseAdapter {
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);
}

View File

@@ -9,10 +9,21 @@ 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.
*
@@ -38,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")
@@ -46,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();
@@ -57,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.
*/
@@ -102,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");
}
@@ -113,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;
}
}

View File

@@ -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) {

Some files were not shown because too many files have changed in this diff Show More