Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SponsorBlock Implementation #3205

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c69ce32
SponsorBlock: Init
polymorphicshade Mar 8, 2020
d67a8e1
SponsorBlock: Codestyle fixes
polymorphicshade May 15, 2020
d30178f
SponsorBlock: Made the FocusAwareSeekBar extend MarkableSeekBar
polymorphicshade May 15, 2020
193a19d
SponsorBlock: Made changes requested in code review
polymorphicshade May 15, 2020
d5796b1
SponsorBlock: Removed additional things related to the last commit
polymorphicshade May 15, 2020
d17745a
SponsorBlock: Now using XML drawable SponsorBlock icon
polymorphicshade May 15, 2020
7b62bf6
SponsorBlock: Now using nanojson instead of org.json
polymorphicshade May 15, 2020
fea9cbd
SponsorBlock: Add link to privacy policy
Atemu May 15, 2020
89e7128
SponsorBlock: Emphasize that it's a 3rd party service
Atemu May 15, 2020
abf9df3
SponsorBlock: Added the ability to customize the server url
polymorphicshade May 18, 2020
41479dc
SponsorBlock: Changed normal app notification to be a simple toast no…
polymorphicshade Jul 19, 2020
f0b029d
SponsorBlock: Now requires the API url to be set
polymorphicshade Jul 20, 2020
639c238
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Aug 1, 2020
b407ae4
SponsorBlock: Made entering the API Url more user-friendly
polymorphicshade Aug 2, 2020
ed83137
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Aug 4, 2020
a029c0e
SponsorBlock: Added segment categories
polymorphicshade Aug 4, 2020
99810fb
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Aug 5, 2020
8a1e474
SponsorBlock: Improved category settings screen UX
polymorphicshade Aug 5, 2020
9e66a86
SponsorBlock: Added button to player that enables/disables segment sk…
polymorphicshade Aug 6, 2020
f7575da
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Aug 16, 2020
76c649a
SponsorBlock: Changed how MarkableSeekBar draws markers.
polymorphicshade Aug 17, 2020
bf78cbb
SponsorBlock: Improved enable/disable icons
polymorphicshade Aug 19, 2020
2da3dea
SponsorBlock: Made string resource names consistent
polymorphicshade Aug 19, 2020
472089e
SponsorBlock: Tweaked category title text
polymorphicshade Aug 20, 2020
e18579b
SponsorBlock: Added some null checks for the blockSponsorsButton
polymorphicshade Aug 21, 2020
dfb94a2
SponsorBlock: One more blockSponsorsButton null check
polymorphicshade Aug 21, 2020
4cadf54
SponsorBlock: Added exclusion list feature
polymorphicshade Aug 23, 2020
4bfd2b0
SponsorBlock: Made some strings translatable
polymorphicshade Aug 23, 2020
9830781
SponsorBlock: Forgot another pesky null check...
polymorphicshade Aug 23, 2020
4f417b5
SponsorBlock: "exclusion" to "whitelist"
polymorphicshade Aug 24, 2020
7db26f3
SponsorBlock: Fixed button from being cut off on smaller screens
polymorphicshade Aug 26, 2020
62b1091
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Sep 6, 2020
844dc53
SponsorBlock: Fixed rounding issue when marking segments
polymorphicshade Sep 6, 2020
0e810e9
SponsorBlock: Fixed infinite skip loop
polymorphicshade Sep 6, 2020
129d72d
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Sep 17, 2020
5dc035b
SponsorBlock: Getting segments now uses video ID hash
polymorphicshade Sep 17, 2020
f142475
SponsorBlock: Reduced the amount of video ID hash characters sent to …
polymorphicshade Sep 17, 2020
5ed80f4
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Sep 27, 2020
88d16b5
SponsorBlock: Added SponsorBlock icon to layout-large-land player
polymorphicshade Sep 27, 2020
70c2182
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Sep 27, 2020
b038ed6
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Oct 2, 2020
862ace4
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Oct 4, 2020
9313439
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Oct 24, 2020
ba4b412
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Oct 25, 2020
c35dc98
SponsorBlock: Fixed (?) rewinding over skippable segments
polymorphicshade Oct 25, 2020
d4f5738
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Oct 28, 2020
be067dd
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Nov 18, 2020
86b3244
SponsorBlock: Merge branch 'dev' into sponsorblock
polymorphicshade Nov 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions app/src/main/java/org/schabi/newpipe/SponsorBlockApiTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package org.schabi.newpipe;

import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;

import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;

import org.schabi.newpipe.util.VideoSegment;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

public class SponsorBlockApiTask extends AsyncTask<String, Void, JsonArray> {
private static final Application APP = App.getApp();
private String apiUrl;
private static final String TAG = SponsorBlockApiTask.class.getSimpleName();
private static final boolean DEBUG = MainActivity.DEBUG;

public SponsorBlockApiTask(final String apiUrl) {
this.apiUrl = apiUrl;
}

public VideoSegment[] getYouTubeVideoSegments(final String videoId,
final boolean includeSponsorCategory,
final boolean includeIntroCategory,
final boolean includeOutroCategory,
final boolean includeInteractionCategory,
final boolean includeSelfPromoCategory,
final boolean includeMusicCategory)
throws ExecutionException, InterruptedException, UnsupportedEncodingException {

final ArrayList<String> categoryParamList = new ArrayList<>();

if (includeSponsorCategory) {
categoryParamList.add("sponsor");
}
if (includeIntroCategory) {
categoryParamList.add("intro");
}
if (includeOutroCategory) {
categoryParamList.add("outro");
}
if (includeInteractionCategory) {
categoryParamList.add("interaction");
}
if (includeSelfPromoCategory) {
categoryParamList.add("selfpromo");
}
if (includeMusicCategory) {
categoryParamList.add("music_offtopic");
}

if (categoryParamList.size() == 0) {
return null;
}

String categoryParams = "[\"" + TextUtils.join("\",\"", categoryParamList) + "\"]";
categoryParams = URLEncoder.encode(categoryParams, "utf-8");

final String videoIdHash = toSha256(videoId);

if (videoIdHash == null) {
return null;
}

final String params = "skipSegments/" + videoIdHash.substring(0, 4)
+ "?categories=" + categoryParams;

final JsonArray responseArray = execute(params).get();

final ArrayList<VideoSegment> result = new ArrayList<>();

for (final Object obj1 : responseArray) {
final JsonObject jObj1 = (JsonObject) obj1;

final String responseVideoId = jObj1.getString("videoID");
if (!responseVideoId.equals(videoId)) {
continue;
}

final JsonArray segmentArray = (JsonArray) jObj1.get("segments");
if (segmentArray == null) {
continue;
}

for (final Object obj2 : segmentArray) {
final JsonObject jObj2 = (JsonObject) obj2;

final JsonArray segmentInfo = (JsonArray) jObj2.get("segment");
if (segmentInfo == null) {
continue;
}

final double startTime = segmentInfo.getDouble(0) * 1000;
final double endTime = segmentInfo.getDouble(1) * 1000;
final String category = jObj2.getString("category");

final VideoSegment segment = new VideoSegment(startTime, endTime, category);
result.add(segment);
}
}

return result.toArray(new VideoSegment[0]);
}

@Override
protected JsonArray doInBackground(final String... strings) {
if (isCancelled() || !isConnected()) {
return null;
}

try {
final String responseBody =
DownloaderImpl
.getInstance()
.get(apiUrl + strings[0])
.responseBody();

return JsonParser.array().from(responseBody);

} catch (final Exception ex) {
if (DEBUG) {
Log.w(TAG, Log.getStackTraceString(ex));
}
}

return null;
}

private boolean isConnected() {
final ConnectivityManager cm =
(ConnectivityManager) APP.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnected();
}

private String toSha256(final String videoId) {
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] bytes = digest.digest(videoId.getBytes(StandardCharsets.UTF_8));
final StringBuilder sb = new StringBuilder();

for (final byte b : bytes) {
final String hex = Integer.toHexString(0xff & b);

if (hex.length() == 1) {
sb.append('0');
}

sb.append(hex);
}

return sb.toString();
} catch (final Exception e) {
Log.e("SPONSOR_BLOCK", "Error getting video ID hash.", e);
return null;
}
}
}
Loading