diff --git a/sampleApp/src/main/AndroidManifest.xml b/sampleApp/src/main/AndroidManifest.xml
index 070b78d..d5aeea0 100644
--- a/sampleApp/src/main/AndroidManifest.xml
+++ b/sampleApp/src/main/AndroidManifest.xml
@@ -18,6 +18,8 @@
+
+
diff --git a/sampleApp/src/main/java/at/huber/sampleDownload/SampleDownloadActivity.java b/sampleApp/src/main/java/at/huber/sampleDownload/SampleDownloadActivity.java
index e28eb2c..ce96c99 100644
--- a/sampleApp/src/main/java/at/huber/sampleDownload/SampleDownloadActivity.java
+++ b/sampleApp/src/main/java/at/huber/sampleDownload/SampleDownloadActivity.java
@@ -21,7 +21,7 @@
public class SampleDownloadActivity extends Activity {
- private static String youtubeLink;
+ private static String youtubeLink = "https://www.youtube.com/watch?v=DZrTFdUcWHY";
private LinearLayout mainLayout;
private ProgressBar mainProgressBar;
@@ -52,8 +52,9 @@ && getIntent().getType() != null && "text/plain".equals(getIntent().getType()))
} else if (savedInstanceState != null && youtubeLink != null) {
getYoutubeDownloadUrl(youtubeLink);
} else {
- finish();
+ //finish();
}
+ getYoutubeDownloadUrl(youtubeLink);
}
private void getYoutubeDownloadUrl(String youtubeLink) {
diff --git a/youtubeExtractor/build.gradle b/youtubeExtractor/build.gradle
index d35602a..2295993 100644
--- a/youtubeExtractor/build.gradle
+++ b/youtubeExtractor/build.gradle
@@ -17,6 +17,7 @@ dependencies {
exclude module: 'appcompat-v7'
}
implementation 'com.android.support:support-annotations:28.0.0'
+ implementation("com.squareup.okhttp3:okhttp:3.10.0")
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
diff --git a/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/OkHttpHelper.java b/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/OkHttpHelper.java
new file mode 100644
index 0000000..519e7bf
--- /dev/null
+++ b/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/OkHttpHelper.java
@@ -0,0 +1,38 @@
+package at.huber.youtubeExtractor;
+
+import android.support.annotation.NonNull;
+
+import java.io.IOException;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+public abstract class OkHttpHelper {
+
+ public static String makeRequest(@NonNull OkHttpClient client, @NonNull String url) throws IOException {
+ Response response = null;
+ try {
+ final Request request;
+ try {
+ request = new Request.Builder()
+ .url(url)
+ .get()
+ .build();
+ } catch (Exception e) {
+ throw new IOException("Can't create request: " + e.getMessage());
+ }
+ response = client.newCall(request).execute();
+ if (!response.isSuccessful())
+ throw new IOException("Response is not successful: " + response);
+ final ResponseBody body = response.body();
+ if (body == null)
+ throw new IOException("Response body is null: " + response);
+ return body.string();
+ } finally {
+ if (response != null)
+ response.close();
+ }
+ }
+}
diff --git a/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/YouTubeExtractor.java b/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/YouTubeExtractor.java
index 7b02398..810783f 100644
--- a/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/YouTubeExtractor.java
+++ b/youtubeExtractor/src/main/java/at/huber/youtubeExtractor/YouTubeExtractor.java
@@ -5,6 +5,8 @@
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -20,7 +22,6 @@
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.ref.WeakReference;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -31,6 +32,11 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
public abstract class YouTubeExtractor extends AsyncTask> {
private final static boolean CACHING = true;
@@ -81,7 +87,7 @@ public abstract class YouTubeExtractor extends AsyncTask(con);
cacheDirPath = con.getCacheDir().getAbsolutePath();
+
+ mClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(10, TimeUnit.SECONDS)
+ .addInterceptor(new Interceptor() {
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ final Request original = chain.request();
+ final Request header = original.newBuilder()
+ .addHeader("User-Agent", USER_AGENT)
+ .build();
+ return chain.proceed(header);
+ }
+ })
+ .build();
+
}
@Override
@@ -171,6 +198,37 @@ public void extract(String youtubeLink, boolean parseDashManifest, boolean inclu
this.execute(youtubeLink);
}
+ @Nullable
+ public SparseArray extractSync(String youtubeLink, boolean parseDashManifest, boolean includeWebM) {
+ this.includeWebM = includeWebM;
+ videoID = null;
+ String ytUrl = youtubeLink;
+ if (ytUrl == null) {
+ return null;
+ }
+ Matcher mat = patYouTubePageLink.matcher(ytUrl);
+ if (mat.find()) {
+ videoID = mat.group(3);
+ } else {
+ mat = patYouTubeShortLink.matcher(ytUrl);
+ if (mat.find()) {
+ videoID = mat.group(3);
+ } else if (ytUrl.matches("\\p{Graph}+?")) {
+ videoID = ytUrl;
+ }
+ }
+ if (videoID != null) {
+ try {
+ return getStreamUrls();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ Log.e(LOG_TAG, "Wrong YouTube link format");
+ }
+ return null;
+ }
+
protected abstract void onExtractionComplete(SparseArray ytFiles, VideoMeta videoMeta);
@Override
@@ -204,27 +262,15 @@ protected SparseArray doInBackground(String... params) {
}
private SparseArray getStreamUrls() throws IOException, InterruptedException {
-
String ytInfoUrl = (useHttp) ? "http://" : "https://";
ytInfoUrl += "www.youtube.com/get_video_info?video_id=" + videoID + "&eurl="
+ URLEncoder.encode("https://youtube.googleapis.com/v/" + videoID, "UTF-8");
String streamMap;
BufferedReader reader = null;
- URL getUrl = new URL(ytInfoUrl);
- if(LOGGING)
+ if (LOGGING)
Log.d(LOG_TAG, "infoUrl: " + ytInfoUrl);
- HttpURLConnection urlConnection = (HttpURLConnection) getUrl.openConnection();
- urlConnection.setRequestProperty("User-Agent", USER_AGENT);
- try {
- reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
- streamMap = reader.readLine();
-
- } finally {
- if (reader != null)
- reader.close();
- urlConnection.disconnect();
- }
+ streamMap = OkHttpHelper.makeRequest(mClient, ytInfoUrl);
Matcher mat;
String curJsFileName;
SparseArray encSignatures = null;
@@ -234,31 +280,24 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
parseVideoMeta(streamMap);
- if(videoMeta.isLiveStream()){
+ if (videoMeta.isLiveStream()) {
mat = patHlsvp.matcher(streamMap);
- if(mat.find()) {
+ if (mat.find()) {
String hlsvp = URLDecoder.decode(mat.group(1), "UTF-8");
SparseArray ytFiles = new SparseArray<>();
- getUrl = new URL(hlsvp);
- urlConnection = (HttpURLConnection) getUrl.openConnection();
- urlConnection.setRequestProperty("User-Agent", USER_AGENT);
- try {
- reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
- String line;
- while ((line = reader.readLine()) != null) {
- if(line.startsWith("https://") || line.startsWith("http://")){
- mat = patHlsItag.matcher(line);
- if(mat.find()){
- int itag = Integer.parseInt(mat.group(1));
- YtFile newFile = new YtFile(FORMAT_MAP.get(itag), line);
- ytFiles.put(itag, newFile);
- }
- }
+ String[] result = OkHttpHelper.makeRequest(mClient, hlsvp).split("\n");
+ for (String line : result) {
+ if (TextUtils.isEmpty(line))
+ continue;
+ if (line.startsWith("https://") || line.startsWith("http://")) {
+ mat = patHlsItag.matcher(line);
+ if (mat.find()) {
+ int itag = Integer.parseInt(mat.group(1));
+ YtFile newFile = new YtFile(FORMAT_MAP.get(itag), line);
+ ytFiles.put(itag, newFile);
+ }
}
- } finally {
- reader.close();
- urlConnection.disconnect();
}
if (ytFiles.size() == 0) {
@@ -274,7 +313,7 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
// "use_cipher_signature" disappeared, we check whether at least one ciphered signature
// exists int the stream_map.
boolean sigEnc = true, statusFail = false;
- if(!patCipher.matcher(streamMap).find()) {
+ if (!patCipher.matcher(streamMap).find()) {
sigEnc = false;
if (!patStatusOk.matcher(streamMap).find()) {
statusFail = true;
@@ -292,24 +331,18 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
if (LOGGING)
Log.d(LOG_TAG, "Get from youtube page");
- getUrl = new URL("https://youtube.com/watch?v=" + videoID);
- urlConnection = (HttpURLConnection) getUrl.openConnection();
- urlConnection.setRequestProperty("User-Agent", USER_AGENT);
- try {
- reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
- String line;
- while ((line = reader.readLine()) != null) {
- // Log.d("line", line);
- mat = patYtPlayer.matcher(line);
- if (mat.find()) {
- streamMap = line.replace("\\\"", "\"");
- break;
- }
+ String[] result = OkHttpHelper.makeRequest(
+ mClient, "https://youtube.com/watch?v=" + videoID).split("\n");
+ for (String line : result) {
+ if (TextUtils.isEmpty(line))
+ continue;
+ mat = patYtPlayer.matcher(line);
+ if (mat.find()) {
+ streamMap = line.replace("\\\"", "\"");
+ break;
}
- } finally {
- reader.close();
- urlConnection.disconnect();
}
+
encSignatures = new SparseArray<>();
mat = patDecryptionJsFile.matcher(streamMap);
@@ -329,8 +362,7 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
if (sigEnc) {
mat = patCipher.matcher(streamMap);
- }
- else {
+ } else {
mat = patUrl.matcher(streamMap);
}
@@ -388,7 +420,7 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
if (encSignatures != null) {
if (LOGGING)
- Log.d(LOG_TAG, "Decipher signatures: " + encSignatures.size()+ ", videos: " + ytFiles.size());
+ Log.d(LOG_TAG, "Decipher signatures: " + encSignatures.size() + ", videos: " + ytFiles.size());
String signature;
decipheredSignature = null;
if (decipherSignature(encSignatures)) {
@@ -407,7 +439,7 @@ private SparseArray getStreamUrls() throws IOException, InterruptedExcep
for (int i = 0; i < encSignatures.size() && i < sigs.length; i++) {
int key = encSignatures.keyAt(i);
String url = ytFiles.get(key).getUrl();
- url += "&sig=" + sigs[i];
+ url += "&sig=" + sigs[i];
YtFile newFile = new YtFile(FORMAT_MAP.get(key), url);
ytFiles.put(key, newFile);
}
@@ -427,25 +459,16 @@ private boolean decipherSignature(final SparseArray encSignatures) throw
if (decipherFunctionName == null || decipherFunctions == null) {
String decipherFunctUrl = "https://s.ytimg.com/yts/jsbin/" + decipherJsFileName;
- BufferedReader reader = null;
String javascriptFile;
- URL url = new URL(decipherFunctUrl);
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- urlConnection.setRequestProperty("User-Agent", USER_AGENT);
- try {
- reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
- StringBuilder sb = new StringBuilder("");
- String line;
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- sb.append(" ");
- }
- javascriptFile = sb.toString();
- } finally {
- if (reader != null)
- reader.close();
- urlConnection.disconnect();
+ String[] result = OkHttpHelper.makeRequest(mClient, decipherFunctUrl).split("\n");
+ StringBuilder sb = new StringBuilder("");
+ for (String line : result) {
+ if (TextUtils.isEmpty(line))
+ continue;
+ sb.append(line);
+ sb.append(" ");
}
+ javascriptFile = sb.toString();
if (LOGGING)
Log.d(LOG_TAG, "Decipher FunctURL: " + decipherFunctUrl);
@@ -551,7 +574,7 @@ private void parseVideoMeta(String getVideoInfo) {
}
mat = patHlsvp.matcher(getVideoInfo);
- if(mat.find())
+ if (mat.find())
isLiveStream = true;
mat = patAuthor.matcher(getVideoInfo);
@@ -651,8 +674,7 @@ private void writeDeciperFunctToChache() {
private void decipherViaWebView(final SparseArray encSignatures) {
final Context context = refContext.get();
- if (context == null)
- {
+ if (context == null) {
return;
}
@@ -689,7 +711,7 @@ public void onResult(String result) {
public void onError(String errorMessage) {
lock.lock();
try {
- if(LOGGING)
+ if (LOGGING)
Log.e(LOG_TAG, errorMessage);
jsExecuting.signal();
} finally {