From eaf098a259ace20c0c03e1ed2305790b5563ec63 Mon Sep 17 00:00:00 2001 From: samfundev Date: Wed, 2 Dec 2020 18:32:41 -0500 Subject: [PATCH] Use embed adblocking technique Closes #148 --- .../twire/fragments/StreamFragment.java | 11 ++- .../twire/tasks/GetLiveStreamURL.java | 93 +++++++++---------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/com/perflyst/twire/fragments/StreamFragment.java b/app/src/main/java/com/perflyst/twire/fragments/StreamFragment.java index 2cf84b59..5ce5e67d 100644 --- a/app/src/main/java/com/perflyst/twire/fragments/StreamFragment.java +++ b/app/src/main/java/com/perflyst/twire/fragments/StreamFragment.java @@ -71,8 +71,8 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.PlayerView; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; +import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; @@ -1445,7 +1445,12 @@ private void tryNextBestQuality(String quality) { * @param url */ private void playUrl(String url) { - DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(), getString(R.string.app_name)); + DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory(getString(R.string.app_name)); + + HttpDataSource.RequestProperties properties = dataSourceFactory.getDefaultRequestProperties(); + properties.set("Referer", "https://player.twitch.tv"); + properties.set("Origin", "https://player.twitch.tv"); + MediaSource mediaSource = new HlsMediaSource.Factory(dataSourceFactory) .createMediaSource( new MediaItem.Builder() diff --git a/app/src/main/java/com/perflyst/twire/tasks/GetLiveStreamURL.java b/app/src/main/java/com/perflyst/twire/tasks/GetLiveStreamURL.java index 49aa47ac..004de05a 100644 --- a/app/src/main/java/com/perflyst/twire/tasks/GetLiveStreamURL.java +++ b/app/src/main/java/com/perflyst/twire/tasks/GetLiveStreamURL.java @@ -3,25 +3,24 @@ import android.os.AsyncTask; import android.util.Log; +import com.perflyst.twire.misc.SecretKeys; import com.perflyst.twire.model.Quality; import com.perflyst.twire.service.Service; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URL; import java.net.URLEncoder; import java.util.LinkedHashMap; import java.util.Random; -import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; + /** * Async task. Gets the required access token for a specific streamer. Then starts the streamers live stream. * Requires to be executed with the username of the streamer and a reference to the videoview @@ -36,17 +35,44 @@ public GetLiveStreamURL(AsyncResponse aCallback) { callback = aCallback; } + protected String formatQuery(boolean isLive, String channelOrVod) + { + return "{\n" + + " \"operationName\": \"PlaybackAccessToken\",\n" + + " \"extensions\": {\n" + + " \"persistedQuery\": {\n" + + " \"version\": 1,\n" + + " \"sha256Hash\": \"0828119ded1c13477966434e15800ff57ddacf13ba1911c129dc2200705b0712\"\n" + + " }\n" + + " },\n" + + " \"variables\": {\n" + + " \"isLive\": " + isLive + ",\n" + + " \"login\": \"" + (isLive ? channelOrVod : "") + "\",\n" + + " \"isVod\": " + !isLive + ",\n" + + " \"vodID\": \"" + (!isLive ? channelOrVod : "") + "\",\n" + + " \"playerType\": \"embed\"\n" + + " }\n" + + "}"; + } + @Override protected LinkedHashMap doInBackground(String... params) { String streamerName = params[0]; String sig = ""; String tokenString = ""; - String resultString = Service.urlToJSONString("https://api.twitch.tv/api/channels/" + streamerName + "/access_token?platform=_"); + Request request = new Request.Builder() + .url("https://gql.twitch.tv/gql") + .header("Client-ID", SecretKeys.TWITCH_WEB_CLIENT_ID) + .post(RequestBody.create(MediaType.get("application/json"), formatQuery(true, streamerName))) + .build(); + + String resultString = Service.urlToJSONString(request); try { JSONObject resultJSON = new JSONObject(resultString); - tokenString = resultJSON.getString("token"); - sig = resultJSON.getString("sig"); + JSONObject tokenJSON = resultJSON.getJSONObject("data").getJSONObject("streamPlaybackAccessToken"); + tokenString = tokenJSON.getString("value"); + sig = tokenJSON.getString("signature"); Log.d("ACCESS_TOKEN_STRING", tokenString); } catch (JSONException e) { @@ -72,51 +98,22 @@ protected void onPostExecute(LinkedHashMap result) { } LinkedHashMap parseM3U8(String urlToRead) { - URL url; - HttpURLConnection conn = null; - Scanner in = null; - String line; - StringBuilder result = new StringBuilder(); + Request request = new Request.Builder() + .url(urlToRead) + .header("Referer", "https://player.twitch.tv") + .header("Origin", "https://player.twitch.tv") + .build(); - try { - url = new URL(urlToRead.replace(" ", "%20")); - - conn = Service.openConnection(url); - conn.setReadTimeout(3000); - conn.setConnectTimeout(3000); - conn.setRequestMethod("GET"); - - InputStream inputs; - if (conn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) { - inputs = conn.getInputStream(); - } else { - // Error - inputs = conn.getErrorStream(); - } - - in = new Scanner(new InputStreamReader(inputs)); - - while (in.hasNextLine()) { - line = in.nextLine(); - result.append(line).append("\n"); - } - - in.close(); - conn.disconnect(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (in != null) - in.close(); - if (conn != null) - conn.disconnect(); - } + String result = ""; + Service.SimpleResponse response = Service.makeRequest(request); + if (response != null) + result = response.body; LinkedHashMap resultList = new LinkedHashMap<>(); resultList.put(QUALITY_AUTO, new Quality("Auto", urlToRead)); Pattern p = Pattern.compile("GROUP-ID=\"(.+)\",NAME=\"(.+)\".+\\n.+\\n(http://\\S+)"); - Matcher m = p.matcher(result.toString()); + Matcher m = p.matcher(result); while (m.find()) { resultList.put(m.group(1), new Quality(m.group(2), m.group(3)));