From 682437a77411d218c7a6d6b377a84ee988c25a73 Mon Sep 17 00:00:00 2001 From: FongMi Date: Tue, 21 Mar 2023 10:01:30 +0800 Subject: [PATCH] Support youtube parser --- .../com/fongmi/android/tv/bean/Channel.java | 7 ++- .../android/tv/model/LiveViewModel.java | 2 + .../android/tv/player/source/Youtube.java | 54 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/fongmi/android/tv/player/source/Youtube.java diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java index b4c7a65a6..b35782cd9 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java @@ -8,6 +8,7 @@ import android.widget.ImageView; import com.fongmi.android.tv.R; import com.fongmi.android.tv.utils.ImgUtil; import com.fongmi.android.tv.utils.ResUtil; +import com.google.common.net.HttpHeaders; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; @@ -221,10 +222,14 @@ public class Channel { return getScheme().startsWith("tvbus"); } + public boolean isYoutube() { + return Uri.parse(getCurrent()).getHost().equals("www.youtube.com"); + } + public Map getHeaders() { HashMap map = new HashMap<>(); if (getUa().isEmpty()) return map; - map.put("User-Agent", getUa()); + map.put(HttpHeaders.USER_AGENT, getUa()); return map; } diff --git a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java index 2a404211a..8fcdf0b02 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java @@ -9,6 +9,7 @@ import com.fongmi.android.tv.bean.Channel; import com.fongmi.android.tv.bean.Live; import com.fongmi.android.tv.player.source.Force; import com.fongmi.android.tv.player.source.TVBus; +import com.fongmi.android.tv.player.source.Youtube; import com.fongmi.android.tv.player.source.ZLive; import java.util.concurrent.Callable; @@ -44,6 +45,7 @@ public class LiveViewModel extends ViewModel { if (item.isForce()) item.setUrl(Force.get().fetch(url)); else if (item.isZLive()) item.setUrl(ZLive.get().fetch(url)); else if (item.isTVBus()) item.setUrl(TVBus.get().fetch(url)); + else if (item.isYoutube()) item.setUrl(Youtube.get().fetch(url)); else item.setUrl(url); return item; }); diff --git a/app/src/main/java/com/fongmi/android/tv/player/source/Youtube.java b/app/src/main/java/com/fongmi/android/tv/player/source/Youtube.java new file mode 100644 index 000000000..349d59312 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/player/source/Youtube.java @@ -0,0 +1,54 @@ +package com.fongmi.android.tv.player.source; + +import com.fongmi.android.tv.net.OkHttp; +import com.google.common.net.HttpHeaders; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import okhttp3.Headers; + +public class Youtube { + + private static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"; + + private static class Loader { + static volatile Youtube INSTANCE = new Youtube(); + } + + public static Youtube get() { + return Loader.INSTANCE; + } + + public String fetch(String url) { + try { + String result = OkHttp.newCall(url, Headers.of(HttpHeaders.USER_AGENT, CHROME)).execute().body().string(); + Pattern pattern = Pattern.compile("hlsManifestUrl\\S*?(https\\S*?\\.m3u8)"); + Matcher matcher = pattern.matcher(result); + if (!matcher.find()) return ""; + String stable = matcher.group(1); + result = OkHttp.newCall(stable, Headers.of(HttpHeaders.USER_AGENT, CHROME)).execute().body().string(); + String quality = find(result); + return quality.isEmpty() ? url : quality; + } catch (Exception e) { + e.printStackTrace(); + return url; + } + } + + private String find(String result) { + String url = ""; + List items = Arrays.asList("301", "300", "96", "95", "94"); + for (String item : items) if (!(url = find(result, "https:\\/.*\\/" + item + "\\/.*index.m3u8")).isEmpty()) break; + return url; + } + + private String find(String result, String rule) { + Pattern pattern = Pattern.compile(rule); + Matcher matcher = pattern.matcher(result); + if (matcher.find()) return matcher.group(); + return ""; + } +}