1
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-09-20 11:20:52 +02:00

Compare commits

...

18 Commits

Author SHA1 Message Date
Christian Schabesberger
f67158a2a7 Fixed:
- made "could not find a streamingplayer" thing inside ActionBarHandler yield stacktraces
- remove watermark
- fixed fab layout
- changed version number to 0.5.0
2015-10-29 18:37:32 +01:00
Christian Schabesberger
c22c2009d4 - changed icon again
- made ActionBarHandler not be a singelton anymore
 - fixed go back bug for the "Next Video" thing
 - fixed opening youtube mobile links
2015-10-29 17:56:35 +01:00
Christian Schabesberger
ab4d626ea9 fixed opening videos via firefox/fenec 2015-10-28 20:48:03 +01:00
Christian Schabesberger
96709d22e9 Merge pull request #61 from Natureshadow/patch-1
Add missing patterns as described in isue #50
2015-10-28 19:39:06 +01:00
Christian Schabesberger
f0bd171eee small layout changed in README.md 2015-10-28 19:08:58 +01:00
Dominik George
c4191077f3 Add missing patterns as described in isue #50 2015-10-28 15:24:46 +01:00
Christian Schabesberger
321d090052 - added dracon5's website to README.md
- added halcyonest icon (with smal modifications)
2015-10-27 21:35:08 +01:00
Christian Schabesberger
32dcb4d281 improved README file 2015-10-27 20:01:56 +01:00
Christian Schabesberger
080159849e - added preference for "next video" item
- display if a url is supported or nod
2015-10-27 18:13:04 +01:00
Christian Schabesberger
d9e690f62c added NextVideo support 2015-10-25 19:14:29 +01:00
Christian Schabesberger
8c0156dea3 fixed broken commit 2015-10-24 16:05:23 +02:00
Christian Schabesberger
038c59ce66 fiexed some smaller displaying errors 2015-10-24 16:04:27 +02:00
Christian Schabesberger
72e08c0447 fixed some layout bugs 2015-10-23 23:08:01 +02:00
Christian Schabesberger
173eaa8cf8 Merge pull request #51 from Soofe/master
Fixed some typos and removed unused imports.
2015-10-17 17:22:21 +02:00
Christian Schabesberger
a04cd24e5e Merge pull request #53 from pejakm/srupd
Update Serbian translation
2015-10-17 17:15:53 +02:00
Mladen Pejaković
0e11404b3b Update Serbian translation 2015-10-17 17:13:21 +02:00
Soofe
342807e26a Update VideoItemListFragment.java 2015-10-15 23:58:14 +02:00
Soofe
c068f08ff8 Fixed some typos and removed unused imports. 2015-10-15 23:25:53 +02:00
36 changed files with 1775 additions and 381 deletions

View File

@@ -1,7 +1,45 @@
NewPipe
-------
# NewPipe
[![Translation Status](https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg)](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.
[![NewPipe](https://f-droid.org/repo/icons/org.schabi.newpipe.4.png)](http://dasochan.nl/newpipe/)
NewPipe: A free lightweight Youtube fronted 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...
[![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.
## 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
## Coming Features
* Shows Next/Related videos
* 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. 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.
# Help is always welcome !!!
Whether its about ideas, translation, design changes, code cleaning, or real heavy code changes. Help is always welcome.
The more is done the better it gets!

View File

@@ -71,9 +71,10 @@
<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/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" />
@@ -91,11 +92,12 @@
</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.0.1" 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.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" />
<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 4
versionName "0.4.1"
versionCode 5
versionName "0.5.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 'org.jsoup:jsoup:1.8.3'
compile 'org.mozilla:rhino:1.7.7'
compile 'com.android.support:design:23.0.1'
compile 'com.android.support:design:23.1.0'
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,5 @@
package org.schabi.newpipe;
import android.graphics.Bitmap;
/**
* Created by Christian Schabesberger on 10.08.15.
*

View File

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

View File

@@ -1,7 +1,5 @@
package org.schabi.newpipe;
import android.graphics.Bitmap;
import java.util.Vector;
/**

View File

@@ -110,13 +110,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;
}

View File

@@ -31,4 +31,5 @@ public class VideoInfoItem {
public Bitmap thumbnail = null;
public String webpage_url = "";
public String upload_date = "";
public String view_count = "";
}

View File

@@ -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.dummi_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 {
//tewak if nececeary: This is a hack preventing to have a 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;
}
}

View File

@@ -1,22 +1,14 @@
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.util.Log;
import android.support.v7.app.AppCompatActivity;
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 +33,11 @@ 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;
private Menu menu = null;
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
@@ -83,6 +76,10 @@ public class VideoItemDetailActivity extends AppCompatActivity {
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
@@ -121,17 +131,15 @@ public class VideoItemDetailActivity extends AppCompatActivity {
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;
}
}

View File

@@ -2,21 +2,14 @@ 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.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.support.v7.widget.SearchView;
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;
/**
@@ -48,6 +41,8 @@ public class VideoItemListActivity extends AppCompatActivity
private String searchQuery = "";
private VideoItemListFragment listFragment;
private VideoItemDetailFragment videoFragment = null;
Menu menu = null;
public class SearchVideoQueryListener implements SearchView.OnQueryTextListener {
@@ -68,7 +63,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 +76,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.
@@ -114,7 +101,6 @@ public class VideoItemListActivity extends AppCompatActivity
searchQuery = savedInstanceState.getString(QUERY);
currentStreamingServiceId = savedInstanceState.getInt(STREAMING_SERVICE);
if(!searchQuery.isEmpty()) {
hideWatermark();
listFragment.search(searchQuery);
}
}
@@ -139,9 +125,6 @@ public class VideoItemListActivity extends AppCompatActivity
searchView.setIconifiedByDefault(false);
searchView.setIconified(false);
searchView.setOnQueryTextListener(new SearchVideoQueryListener());
ActionBarHandler.getHandler().setupNavMenu(this);
}
SettingsActivity.initSettings(this);
@@ -167,10 +150,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 +174,11 @@ public class VideoItemListActivity extends AppCompatActivity
}
public boolean onCreatePanelMenu(int featured, Menu menu) {
super.onCreatePanelMenu(featured, menu);
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.menu = menu;
MenuInflater inflater = getMenuInflater();
if(findViewById(R.id.videoitem_detail_container) == null) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.videoitem_list, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
@@ -195,9 +186,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;
@@ -210,8 +202,8 @@ public class VideoItemListActivity extends AppCompatActivity
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
} else {
ActionBarHandler.getHandler().onItemSelected(item, this);
return super.onOptionsItemSelected(item);
return videoFragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
}
return true;
}

View File

@@ -13,7 +13,6 @@ import android.widget.ListView;
import android.widget.Toast;
import java.net.URL;
import java.util.List;
import java.util.Vector;
@@ -54,14 +53,14 @@ public class VideoItemListFragment extends ListFragment {
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);
}
}
@@ -213,7 +212,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,7 +229,7 @@ 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.
}
}

View File

@@ -6,14 +6,12 @@ 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.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,18 +31,20 @@ 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) {
@@ -96,30 +96,7 @@ 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));
@@ -129,9 +106,4 @@ public class VideoListAdapter extends BaseAdapter {
return convertView;
}
private class ViewHolder {
public ImageView itemThumbnailView;
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView;
}
}

View File

@@ -1,30 +1,29 @@
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 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.VideoInfo;
import org.schabi.newpipe.VideoInfoItem;
import org.xmlpull.v1.XmlPullParser;
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.parser.Parser;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptableObject;
import org.schabi.newpipe.VideoInfoItem;
import org.xmlpull.v1.XmlPullParser;
import java.util.regex.Pattern;
/**
* Created by Christian Schabesberger on 06.08.15.
@@ -48,8 +47,6 @@ 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.
@@ -93,7 +90,7 @@ public class YoutubeExtractor implements Extractor {
}
}
private String decryptoinCode = "";
private String decryptionCode = "";
private static final String DECRYPTION_FUNC_NAME="decrypt";
@Override
@@ -101,7 +98,12 @@ public class YoutubeExtractor implements Extractor {
try {
URI uri = new URI(videoUrl);
if(uri.getHost().contains("youtube")) {
String query = uri.getQuery();
String query = uri.getFragment();
if(query == null) {
query = uri.getQuery();
} else {
query = query.replace("/watch?", "");
}
String queryElements[] = query.split("&");
Map<String, String> queryArguments = new HashMap<>();
for (String e : queryElements) {
@@ -156,7 +158,7 @@ public class YoutubeExtractor implements Extractor {
//-------------------------------------
JSONObject playerArgs = null;
JSONObject ytAssets = null;
String dashManifest = "";
String dashManifest;
{
Pattern p = Pattern.compile("ytplayer.config\\s*=\\s*(\\{.*?\\});");
Matcher m = p.matcher(site);
@@ -183,18 +185,23 @@ public class YoutubeExtractor implements Extractor {
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);
if(decryptionCode.isEmpty()) {
decryptionCode = loadDecryptionCode(playerUrl);
}
// extract audio
videoInfo.audioStreams = parseDashManifest(dashManifest, decryptoinCode);
try {
dashManifest = playerArgs.getString("dashmpd");
videoInfo.audioStreams = parseDashManifest(dashManifest, decryptionCode);
} catch (Exception e) {
//todo: check if the following statement is true
Log.e(TAG, "Dash manifest seems not to bee available.");
e.printStackTrace();
}
//------------------------------------
// extract video stream url
@@ -213,10 +220,10 @@ public class YoutubeExtractor implements Extractor {
// if video has a signature: decrypt it and add it to the url
if(tags.get("s") != null) {
if(decryptoinCode.isEmpty()) {
decryptoinCode = loadDecryptioinCode(playerUrl);
if(decryptionCode.isEmpty()) {
decryptionCode = loadDecryptionCode(playerUrl);
}
streamUrl = streamUrl + "&signature=" + decryptSignature(tags.get("s"), decryptoinCode);
streamUrl = streamUrl + "&signature=" + decryptSignature(tags.get("s"), decryptionCode);
}
if(resolveFormat(itag) != -1) {
@@ -236,7 +243,7 @@ public class YoutubeExtractor implements Extractor {
}
//-------------------------------
// extrating from html page
// extracting from html page
//-------------------------------
@@ -297,32 +304,28 @@ public class YoutubeExtractor implements Extractor {
// view count
videoInfo.view_count = doc.select("div[class=\"watch-view-count\"]").first().text();
/* todo finish this code
// next video
videoInfo.nextVideo = extractVideoInfoItem(doc.select("div[class=\"watch-sidebar-section\"]").first()
.select("li").first());
int i = 0;
// related videos
videoInfo.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));
videoInfo.relatedVideos.add(extractVideoInfoItem(li));
i++;
}
}
*/
return videoInfo;
}
private VideoInfo.AudioStream[] parseDashManifest(String dashManifest, String decryptoinCode) {
if(!dashManifest.contains("/signature/")) {
String encryptedSig = "";
String decryptedSig = "";
String decryptedSig;
try {
Pattern p = Pattern.compile("/s/([a-fA-F0-9\\.]+)");
Matcher m = p.matcher(dashManifest);
@@ -406,11 +409,10 @@ public class YoutubeExtractor implements Extractor {
} catch (Exception e) {
e.printStackTrace();
}
info.title = li.select("span[class=\"title\"]").first()
.text();
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,7 +423,9 @@ 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;
}
@@ -438,7 +442,7 @@ public class YoutubeExtractor implements Extractor {
return retval;
}
private String loadDecryptioinCode(String playerUrl) {
private String loadDecryptionCode(String playerUrl) {
String playerCode = Downloader.download(playerUrl);
String decryptionFuncName = "";
String decryptionFunc = "";

View File

@@ -1,18 +1,17 @@
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 java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Christian Schabesberger on 09.08.15.

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -7,8 +7,9 @@
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"/>

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -3,7 +3,7 @@
<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="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>
@@ -45,4 +45,7 @@
<item>Video</item>
<item>Audio</item>
</string-array>
<string name="nextVideoTitle">Nächstes Video</string>
<string name="showNextVideoTitle">Zeige \"Nächstes Video\" Auswahl.</string>
<string name="urlNotSupportedText">Url wird nicht unterstützt.</string>
</resources>

View File

@@ -29,4 +29,20 @@
<string name="autoPlayThroughIntentTitle">Аутопуштање преко Интента</string>
<string name="autoPlayThroughIntentSummary">Аутоматски почиње пушта видео по позиву из друге апликације.</string>
<string name="defaultResolutionPreferenceTitle">Подразумевана резолуција</string>
</resources>
<string name="playWithKodiTitle">Пусти помоћу Кодија</string>
<string name="koreNotFound">Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру.</string>
<string name="installeKore">Инсталирај Кор</string>
<string name="fdroidKoreUrl">https://f-droid.org/repository/browse/?fdfilter=Kore&amp;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>
</resources>

View File

@@ -23,4 +23,5 @@
<item>m4a</item>
</string-array>
<string name="defaultAudioFormat">m4a</string>
<string name="showNextVideo">show_next_video</string>
</resources>

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