Merge pull request #72 from medavox/master
Code cleanup & minor additions
This commit is contained in:
commit
c51a5a51f1
|
@ -1,3 +1,4 @@
|
|||
.gitignore
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
|
@ -5,3 +6,5 @@
|
|||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.idea/gradle.xml
|
||||
.idea/misc.xml
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
.gitignore
|
||||
/build
|
||||
app/app.iml
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
<activity android:name=".PlayVideoActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/FullscreenTheme"
|
||||
android:parentActivityName=".VideoItemDetailActivity"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.BufferedReader;
|
|||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 14.08.15.
|
||||
|
@ -45,7 +46,13 @@ 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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class VideoInfo {
|
|||
|
||||
public static final int VIDEO_AVAILABLE = 0x00;
|
||||
public static final int VIDEO_UNAVAILABLE = 0x01;
|
||||
public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;
|
||||
public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;//German DRM organisation; sound pretty draconian
|
||||
|
||||
public static String getNameById(int id) {
|
||||
switch(id) {
|
||||
|
@ -68,8 +68,7 @@ public class VideoInfo {
|
|||
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.");
|
||||
default: formatNotKnown(id);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -81,8 +80,7 @@ public class VideoInfo {
|
|||
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.");
|
||||
default: formatNotKnown(id);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -94,8 +92,7 @@ public class VideoInfo {
|
|||
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.");
|
||||
default: formatNotKnown(id);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -109,6 +106,11 @@ public class VideoInfo {
|
|||
public String resolution = "";
|
||||
}
|
||||
|
||||
protected static void formatNotKnown(int id) {
|
||||
Log.e(TAG, "format not known: \"" +
|
||||
Integer.toString(id) + "\". Call the programmers, they messed it up!");
|
||||
}
|
||||
|
||||
public static class AudioStream {
|
||||
public AudioStream(String url, int format, int bandwidth, int samplingRate) {
|
||||
this.url = url; this.format = format;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,8 +67,8 @@ 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();
|
||||
}
|
||||
|
@ -122,9 +122,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);
|
||||
|
|
|
@ -79,16 +79,16 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
|
||||
private class ExtractorRunnable implements Runnable {
|
||||
private Handler h = new Handler();
|
||||
private Class extractorClass;
|
||||
private Extractor extractor;
|
||||
private String videoUrl;
|
||||
public ExtractorRunnable(String videoUrl, Class extractorClass) {
|
||||
this.extractorClass = extractorClass;
|
||||
|
||||
public ExtractorRunnable(String videoUrl, Extractor extractor, VideoItemDetailFragment f) {
|
||||
this.extractor = extractor;
|
||||
this.videoUrl = videoUrl;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Extractor extractor = (Extractor) extractorClass.newInstance();
|
||||
VideoInfo videoInfo = extractor.getVideoInfo(videoUrl);
|
||||
h.post(new VideoResultReturnedRunnable(videoInfo));
|
||||
if (videoInfo.videoAvailableStatus == VideoInfo.VIDEO_AVAILABLE) {
|
||||
|
@ -173,7 +173,7 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
}
|
||||
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
// No god programm design i know. :/
|
||||
// Not good program design, I know. :/
|
||||
Log.w(TAG, "updateThumbnail(): Fragment closed before thread ended work");
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,8 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
StreamingService streamingService = ServiceList.getService(
|
||||
getArguments().getInt(STREAMING_SERVICE));
|
||||
extractorThread = new Thread(new ExtractorRunnable(
|
||||
getArguments().getString(VIDEO_URL), streamingService.getExtractorClass()));
|
||||
getArguments().getString(VIDEO_URL), streamingService.getExtractorInstance(), this));
|
||||
|
||||
autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY);
|
||||
extractorThread.start();
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -106,6 +106,7 @@ public class VideoItemListActivity extends AppCompatActivity
|
|||
//-------- remove this line when multiservice support is implemented ----------
|
||||
currentStreamingServiceId = ServiceList.getIdOfService("Youtube");
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
listFragment = (VideoItemListFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.videoitem_list);
|
||||
listFragment.setStreamingService(ServiceList.getService(currentStreamingServiceId));
|
||||
|
|
|
@ -72,14 +72,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;
|
||||
|
@ -89,13 +89,6 @@ 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);
|
||||
if(run) {
|
||||
|
@ -197,7 +190,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();
|
||||
}
|
||||
|
@ -252,10 +246,6 @@ public class VideoItemListFragment extends ListFragment {
|
|||
}
|
||||
}
|
||||
|
||||
void displayList() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The serialization (saved instance state) Bundle key representing the
|
||||
* activated item position. Only used on tablets.
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.youtube;
|
|||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
@ -50,7 +51,7 @@ public class YoutubeExtractor implements Extractor {
|
|||
private static final String TAG = YoutubeExtractor.class.toString();
|
||||
|
||||
// These lists only contain itag formats that are supported by the common Android Video player.
|
||||
// How ever if you are heading for a list showing all itag formats lock at
|
||||
// How ever if you are heading for a list showing all itag formats look at
|
||||
// https://github.com/rg3/youtube-dl/issues/1687
|
||||
|
||||
public static int resolveFormat(int itag) {
|
||||
|
@ -141,14 +142,7 @@ public class YoutubeExtractor implements Extractor {
|
|||
|
||||
Document doc = Jsoup.parse(site, siteUrl);
|
||||
|
||||
try {
|
||||
Pattern p = Pattern.compile("v=([0-9a-zA-Z]*)");
|
||||
Matcher m = p.matcher(siteUrl);
|
||||
m.find();
|
||||
videoInfo.id = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
videoInfo.id = matchGroup1("v=([0-9a-zA-Z]*)", siteUrl);
|
||||
|
||||
videoInfo.age_limit = 0;
|
||||
videoInfo.webpage_url = siteUrl;
|
||||
|
@ -160,16 +154,14 @@ public class YoutubeExtractor implements Extractor {
|
|||
JSONObject ytAssets = null;
|
||||
String dashManifest;
|
||||
{
|
||||
Pattern p = Pattern.compile("ytplayer.config\\s*=\\s*(\\{.*?\\});");
|
||||
Matcher m = p.matcher(site);
|
||||
m.find();
|
||||
String jsonString = matchGroup1("ytplayer.config\\s*=\\s*(\\{.*?\\});", site);
|
||||
|
||||
try {
|
||||
playerArgs = (new JSONObject(m.group(1)))
|
||||
.getJSONObject("args");
|
||||
ytAssets = (new JSONObject(m.group(1)))
|
||||
.getJSONObject("assets");
|
||||
}catch (Exception e) {
|
||||
JSONObject jsonObj = new JSONObject(jsonString);
|
||||
playerArgs = jsonObj.getJSONObject("args");
|
||||
ytAssets = jsonObj.getJSONObject("assets");
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// If we fail in this part the video is most likely not available.
|
||||
// Determining why is done later.
|
||||
|
@ -199,7 +191,7 @@ public class YoutubeExtractor implements Extractor {
|
|||
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.");
|
||||
Log.e(TAG, "Dash manifest doesn't seem to be available.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -263,15 +255,9 @@ public class YoutubeExtractor implements Extractor {
|
|||
// upload date
|
||||
videoInfo.upload_date = doc.select("strong[class=\"watch-time-text\"").first()
|
||||
.text();
|
||||
|
||||
// Try to only use date not the text around it
|
||||
try {
|
||||
Pattern p = Pattern.compile("([0-9.]*$)");
|
||||
Matcher m = p.matcher(videoInfo.upload_date);
|
||||
m.find();
|
||||
videoInfo.upload_date = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
videoInfo.upload_date = matchGroup1("([0-9.]*$)", videoInfo.upload_date);
|
||||
|
||||
// description
|
||||
videoInfo.description = doc.select("p[id=\"eow-description\"]").first()
|
||||
|
@ -322,16 +308,9 @@ public class YoutubeExtractor implements Extractor {
|
|||
|
||||
private VideoInfo.AudioStream[] parseDashManifest(String dashManifest, String decryptoinCode) {
|
||||
if(!dashManifest.contains("/signature/")) {
|
||||
String encryptedSig = "";
|
||||
String encryptedSig = matchGroup1("/s/([a-fA-F0-9\\.]+)", dashManifest);
|
||||
String decryptedSig;
|
||||
try {
|
||||
Pattern p = Pattern.compile("/s/([a-fA-F0-9\\.]+)");
|
||||
Matcher m = p.matcher(dashManifest);
|
||||
m.find();
|
||||
encryptedSig = m.group(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
decryptedSig = decryptSignature(encryptedSig, decryptoinCode);
|
||||
dashManifest = dashManifest.replace("/s/" + encryptedSig, "/signature/" + decryptedSig);
|
||||
}
|
||||
|
@ -396,10 +375,7 @@ public class YoutubeExtractor implements Extractor {
|
|||
info.webpage_url = li.select("a[class*=\"content-link\"]").first()
|
||||
.attr("abs:href");
|
||||
try {
|
||||
Pattern p = Pattern.compile("v=([0-9a-zA-Z-]*)");
|
||||
Matcher m = p.matcher(info.webpage_url);
|
||||
m.find();
|
||||
info.id=m.group(1);
|
||||
info.id = matchGroup1("v=([0-9a-zA-Z-]*)", info.webpage_url);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -446,27 +422,15 @@ public class YoutubeExtractor implements Extractor {
|
|||
String decryptionCode;
|
||||
|
||||
try {
|
||||
Pattern p = Pattern.compile("\\.sig\\|\\|([a-zA-Z0-9$]+)\\(");
|
||||
Matcher m = p.matcher(playerCode);
|
||||
m.find();
|
||||
decryptionFuncName = m.group(1);
|
||||
decryptionFuncName = matchGroup1("\\.sig\\|\\|([a-zA-Z0-9$]+)\\(", playerCode);
|
||||
|
||||
String functionPattern = "(function " + decryptionFuncName.replace("$", "\\$") + "\\([a-zA-Z0-9_]*\\)\\{.+?\\})";
|
||||
p = Pattern.compile(functionPattern);
|
||||
m = p.matcher(playerCode);
|
||||
m.find();
|
||||
decryptionFunc = m.group(1);
|
||||
decryptionFunc = matchGroup1(functionPattern, playerCode);
|
||||
|
||||
p = Pattern.compile(";([A-Za-z0-9_\\$]{2})\\...\\(");
|
||||
m = p.matcher(decryptionFunc);
|
||||
m.find();
|
||||
helperObjectName = m.group(1);
|
||||
helperObjectName = matchGroup1(";([A-Za-z0-9_\\$]{2})\\...\\(", decryptionFunc);
|
||||
|
||||
String helperPattern = "(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)function";
|
||||
p = Pattern.compile(helperPattern);
|
||||
m = p.matcher(playerCode);
|
||||
m.find();
|
||||
helperObject = m.group(1);
|
||||
helperObject = matchGroup1(helperPattern, playerCode);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -493,4 +457,11 @@ public class YoutubeExtractor implements Extractor {
|
|||
Context.exit();
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private String matchGroup1(String pattern, String input) {
|
||||
Pattern pat = Pattern.compile(pattern);
|
||||
Matcher mat = pat.matcher(input);
|
||||
mat.find();
|
||||
return mat.group(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,14 +57,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 +102,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 +113,6 @@ public class YoutubeSearchEngine implements SearchEngine {
|
|||
Log.e(TAG, "GREAT FUCKING ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue