Skip to content

Commit 99aae7e

Browse files
committed
Merge branch 'dev' into refactor
2 parents 407d2d7 + c6e1721 commit 99aae7e

File tree

308 files changed

+4003
-708
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

308 files changed

+4003
-708
lines changed

app/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ android {
2727
if (System.properties.containsKey('versionCodeOverride')) {
2828
versionCode System.getProperty('versionCodeOverride') as Integer
2929
} else {
30-
versionCode 1002
30+
versionCode 1003
3131
}
32-
versionName "0.27.5"
32+
versionName "0.27.6"
3333
if (System.properties.containsKey('versionNameSuffix')) {
3434
versionNameSuffix System.getProperty('versionNameSuffix')
3535
}
@@ -233,6 +233,7 @@ dependencies {
233233
implementation libs.androidx.work.runtime
234234
implementation libs.androidx.work.rxjava3
235235
implementation libs.androidx.material
236+
implementation libs.androidx.webkit
236237

237238
/** Third-party libraries **/
238239
// Instance state boilerplate elimination

app/src/main/assets/po_token.html

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<!DOCTYPE html>
2+
<html lang="en"><head><title></title><script>
3+
/**
4+
* Factory method to create and load a BotGuardClient instance.
5+
* @param options - Configuration options for the BotGuardClient.
6+
* @returns A promise that resolves to a loaded BotGuardClient instance.
7+
*/
8+
function loadBotGuard(challengeData) {
9+
this.vm = this[challengeData.globalName];
10+
this.program = challengeData.program;
11+
this.vmFunctions = {};
12+
this.syncSnapshotFunction = null;
13+
14+
if (!this.vm)
15+
throw new Error('[BotGuardClient]: VM not found in the global object');
16+
17+
if (!this.vm.a)
18+
throw new Error('[BotGuardClient]: Could not load program');
19+
20+
const vmFunctionsCallback = function (
21+
asyncSnapshotFunction,
22+
shutdownFunction,
23+
passEventFunction,
24+
checkCameraFunction
25+
) {
26+
this.vmFunctions = {
27+
asyncSnapshotFunction: asyncSnapshotFunction,
28+
shutdownFunction: shutdownFunction,
29+
passEventFunction: passEventFunction,
30+
checkCameraFunction: checkCameraFunction
31+
};
32+
};
33+
34+
this.syncSnapshotFunction = this.vm.a(this.program, vmFunctionsCallback, true, this.userInteractionElement, function () {/** no-op */ }, [ [], [] ])[0]
35+
36+
// an asynchronous function runs in the background and it will eventually call
37+
// `vmFunctionsCallback`, however we need to manually tell JavaScript to pass
38+
// control to the things running in the background by interrupting this async
39+
// function in any way, e.g. with a delay of 1ms. The loop is most probably not
40+
// needed but is there just because.
41+
return new Promise(function (resolve, reject) {
42+
i = 0
43+
refreshIntervalId = setInterval(function () {
44+
if (!!this.vmFunctions.asyncSnapshotFunction) {
45+
resolve(this)
46+
clearInterval(refreshIntervalId);
47+
}
48+
if (i >= 10000) {
49+
reject("asyncSnapshotFunction is null even after 10 seconds")
50+
clearInterval(refreshIntervalId);
51+
}
52+
i += 1;
53+
}, 1);
54+
})
55+
}
56+
57+
/**
58+
* Takes a snapshot asynchronously.
59+
* @returns The snapshot result.
60+
* @example
61+
* ```ts
62+
* const result = await botguard.snapshot({
63+
* contentBinding: {
64+
* c: "a=6&a2=10&b=SZWDwKVIuixOp7Y4euGTgwckbJA&c=1729143849&d=1&t=7200&c1a=1&c6a=1&c6b=1&hh=HrMb5mRWTyxGJphDr0nW2Oxonh0_wl2BDqWuLHyeKLo",
65+
* e: "ENGAGEMENT_TYPE_VIDEO_LIKE",
66+
* encryptedVideoId: "P-vC09ZJcnM"
67+
* }
68+
* });
69+
*
70+
* console.log(result);
71+
* ```
72+
*/
73+
function snapshot(args) {
74+
return new Promise(function (resolve, reject) {
75+
if (!this.vmFunctions.asyncSnapshotFunction)
76+
return reject(new Error('[BotGuardClient]: Async snapshot function not found'));
77+
78+
this.vmFunctions.asyncSnapshotFunction(function (response) { resolve(response) }, [
79+
args.contentBinding,
80+
args.signedTimestamp,
81+
args.webPoSignalOutput,
82+
args.skipPrivacyBuffer
83+
]);
84+
});
85+
}
86+
87+
function runBotGuard(challengeData) {
88+
const interpreterJavascript = challengeData.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
89+
90+
if (interpreterJavascript) {
91+
new Function(interpreterJavascript)();
92+
} else throw new Error('Could not load VM');
93+
94+
const webPoSignalOutput = [];
95+
return loadBotGuard({
96+
globalName: challengeData.globalName,
97+
globalObj: this,
98+
program: challengeData.program
99+
}).then(function (botguard) {
100+
return botguard.snapshot({ webPoSignalOutput: webPoSignalOutput })
101+
}).then(function (botguardResponse) {
102+
return { webPoSignalOutput: webPoSignalOutput, botguardResponse: botguardResponse }
103+
})
104+
}
105+
106+
function obtainPoToken(webPoSignalOutput, integrityToken, identifier) {
107+
const getMinter = webPoSignalOutput[0];
108+
109+
if (!getMinter)
110+
throw new Error('PMD:Undefined');
111+
112+
const mintCallback = getMinter(integrityToken);
113+
114+
if (!(mintCallback instanceof Function))
115+
throw new Error('APF:Failed');
116+
117+
const result = mintCallback(identifier);
118+
119+
if (!result)
120+
throw new Error('YNJ:Undefined');
121+
122+
if (!(result instanceof Uint8Array))
123+
throw new Error('ODM:Invalid');
124+
125+
return result;
126+
}
127+
</script></head><body></body></html>

app/src/main/java/org/schabi/newpipe/App.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.acra.config.CoreConfigurationBuilder
2828
import org.schabi.newpipe.error.ReCaptchaActivity
2929
import org.schabi.newpipe.extractor.NewPipe
3030
import org.schabi.newpipe.extractor.downloader.Downloader
31+
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor
3132
import org.schabi.newpipe.ktx.hasAssignableCause
3233
import org.schabi.newpipe.settings.NewPipeSettings
3334
import org.schabi.newpipe.util.BridgeStateSaverInitializer
@@ -36,6 +37,7 @@ import org.schabi.newpipe.util.ServiceHelper
3637
import org.schabi.newpipe.util.StateSaver
3738
import org.schabi.newpipe.util.image.ImageStrategy
3839
import org.schabi.newpipe.util.image.PreferredImageQuality
40+
import org.schabi.newpipe.util.potoken.PoTokenProviderImpl
3941
import java.io.IOException
4042
import java.io.InterruptedIOException
4143
import java.net.SocketException
@@ -116,6 +118,8 @@ open class App :
116118
)
117119

118120
configureRxJavaErrorHandler()
121+
122+
YoutubeStreamExtractor.setPoTokenProvider(PoTokenProviderImpl)
119123
}
120124

121125
override fun newImageLoader(context: Context): ImageLoader =

app/src/main/java/org/schabi/newpipe/DownloaderImpl.java

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -142,46 +142,42 @@ public Response execute(@NonNull final Request request)
142142
}
143143

144144
final okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
145-
.method(httpMethod, requestBody).url(url)
145+
.method(httpMethod, requestBody)
146+
.url(url)
146147
.addHeader("User-Agent", USER_AGENT);
147148

148149
final String cookies = getCookies(url);
149150
if (!cookies.isEmpty()) {
150151
requestBuilder.addHeader("Cookie", cookies);
151152
}
152153

153-
for (final Map.Entry<String, List<String>> pair : headers.entrySet()) {
154-
final String headerName = pair.getKey();
155-
final List<String> headerValueList = pair.getValue();
154+
headers.forEach((headerName, headerValueList) -> {
155+
requestBuilder.removeHeader(headerName);
156+
headerValueList.forEach(headerValue ->
157+
requestBuilder.addHeader(headerName, headerValue));
158+
});
159+
160+
try (
161+
okhttp3.Response response = client.newCall(requestBuilder.build()).execute()
162+
) {
163+
if (response.code() == 429) {
164+
throw new ReCaptchaException("reCaptcha Challenge requested", url);
165+
}
156166

157-
if (headerValueList.size() > 1) {
158-
requestBuilder.removeHeader(headerName);
159-
for (final String headerValue : headerValueList) {
160-
requestBuilder.addHeader(headerName, headerValue);
167+
String responseBodyToReturn = null;
168+
try (ResponseBody body = response.body()) {
169+
if (body != null) {
170+
responseBodyToReturn = body.string();
161171
}
162-
} else if (headerValueList.size() == 1) {
163-
requestBuilder.header(headerName, headerValueList.get(0));
164172
}
165173

174+
final String latestUrl = response.request().url().toString();
175+
return new Response(
176+
response.code(),
177+
response.message(),
178+
response.headers().toMultimap(),
179+
responseBodyToReturn,
180+
latestUrl);
166181
}
167-
168-
final okhttp3.Response response = client.newCall(requestBuilder.build()).execute();
169-
170-
if (response.code() == 429) {
171-
response.close();
172-
173-
throw new ReCaptchaException("reCaptcha Challenge requested", url);
174-
}
175-
176-
final ResponseBody body = response.body();
177-
String responseBodyToReturn = null;
178-
179-
if (body != null) {
180-
responseBodyToReturn = body.string();
181-
}
182-
183-
final String latestUrl = response.request().url().toString();
184-
return new Response(response.code(), response.message(), response.headers().toMultimap(),
185-
responseBodyToReturn, latestUrl);
186182
}
187183
}

app/src/main/java/org/schabi/newpipe/MainActivity.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import org.schabi.newpipe.util.ServiceHelper;
8989
import org.schabi.newpipe.util.StateSaver;
9090
import org.schabi.newpipe.util.ThemeHelper;
91+
import org.schabi.newpipe.util.external_communication.ShareUtils;
9192
import org.schabi.newpipe.views.FocusOverlayView;
9293

9394
import java.util.ArrayList;
@@ -116,7 +117,8 @@ public class MainActivity extends AppCompatActivity {
116117
private static final int ITEM_ID_DOWNLOADS = -4;
117118
private static final int ITEM_ID_HISTORY = -5;
118119
private static final int ITEM_ID_SETTINGS = 0;
119-
private static final int ITEM_ID_ABOUT = 1;
120+
private static final int ITEM_ID_DONATION = 1;
121+
private static final int ITEM_ID_ABOUT = 2;
120122

121123
private static final int ORDER = 0;
122124

@@ -258,6 +260,10 @@ private void addDrawerMenuForCurrentService() throws ExtractionException {
258260
drawerLayoutBinding.navigation.getMenu()
259261
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
260262
.setIcon(R.drawable.ic_settings);
263+
drawerLayoutBinding.navigation.getMenu()
264+
.add(R.id.menu_options_about_group, ITEM_ID_DONATION, ORDER,
265+
R.string.donation_title)
266+
.setIcon(R.drawable.volunteer_activism_ic);
261267
drawerLayoutBinding.navigation.getMenu()
262268
.add(R.id.menu_options_about_group, ITEM_ID_ABOUT, ORDER, R.string.tab_about)
263269
.setIcon(R.drawable.ic_info_outline);
@@ -333,6 +339,9 @@ private void optionsAboutSelected(final MenuItem item) {
333339
case ITEM_ID_SETTINGS:
334340
NavigationHelper.openSettings(this);
335341
break;
342+
case ITEM_ID_DONATION:
343+
ShareUtils.openUrlInBrowser(this, getString(R.string.donation_url));
344+
break;
336345
case ITEM_ID_ABOUT:
337346
NavigationHelper.openAbout(this);
338347
break;
@@ -840,4 +849,5 @@ private boolean bottomSheetHiddenOrCollapsed() {
840849
return sheetState == BottomSheetBehavior.STATE_HIDDEN
841850
|| sheetState == BottomSheetBehavior.STATE_COLLAPSED;
842851
}
852+
843853
}

app/src/main/java/org/schabi/newpipe/error/AcraReportSenderFactory.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.acra.config.CoreConfiguration;
1010
import org.acra.sender.ReportSender;
1111
import org.acra.sender.ReportSenderFactory;
12-
import org.schabi.newpipe.App;
1312

1413
/*
1514
* Created by Christian Schabesberger on 13.09.16.

app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import org.schabi.newpipe.util.ThemeHelper;
2727
import org.schabi.newpipe.util.external_communication.ShareUtils;
2828

29-
import java.time.LocalDateTime;
29+
import java.time.ZonedDateTime;
3030
import java.time.format.DateTimeFormatter;
3131
import java.util.Arrays;
3232
import java.util.stream.Collectors;
@@ -67,10 +67,6 @@ public class ErrorActivity extends AppCompatActivity {
6767
public static final String ERROR_GITHUB_ISSUE_URL =
6868
"https://github.com/TeamNewPipe/NewPipe/issues";
6969

70-
public static final DateTimeFormatter CURRENT_TIMESTAMP_FORMATTER =
71-
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
72-
73-
7470
private ErrorInfo errorInfo;
7571
private String currentTimeStamp;
7672

@@ -107,7 +103,9 @@ protected void onCreate(final Bundle savedInstanceState) {
107103

108104
// important add guru meditation
109105
addGuruMeditation();
110-
currentTimeStamp = CURRENT_TIMESTAMP_FORMATTER.format(LocalDateTime.now());
106+
// print current time, as zoned ISO8601 timestamp
107+
final ZonedDateTime now = ZonedDateTime.now();
108+
currentTimeStamp = now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
111109

112110
activityErrorBinding.errorReportEmailButton.setOnClickListener(v ->
113111
openPrivacyPolicyDialog(this, "EMAIL"));
@@ -250,6 +248,9 @@ private String buildMarkdown() {
250248
.append("\n* __Content Language:__ ").append(getContentLanguageString())
251249
.append("\n* __App Language:__ ").append(getAppLanguage())
252250
.append("\n* __Service:__ ").append(errorInfo.getServiceName())
251+
.append("\n* __Timestamp:__ ").append(currentTimeStamp)
252+
.append("\n* __Package:__ ").append(getPackageName())
253+
.append("\n* __Service:__ ").append(errorInfo.getServiceName())
253254
.append("\n* __Version:__ ").append(BuildConfig.VERSION_NAME)
254255
.append("\n* __OS:__ ").append(getOsString()).append("\n");
255256

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,11 @@ public void onServiceDisconnected() {
282282
/*////////////////////////////////////////////////////////////////////////*/
283283

284284
public static VideoDetailFragment getInstance(final int serviceId,
285-
@Nullable final String videoUrl,
285+
@Nullable final String url,
286286
@NonNull final String name,
287287
@Nullable final PlayQueue queue) {
288288
final VideoDetailFragment instance = new VideoDetailFragment();
289-
instance.setInitialData(serviceId, videoUrl, name, queue);
289+
instance.setInitialData(serviceId, url, name, queue);
290290
return instance;
291291
}
292292

@@ -1726,7 +1726,7 @@ public void onQueueUpdate(final PlayQueue queue) {
17261726
playQueue = queue;
17271727
if (DEBUG) {
17281728
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
1729-
+ serviceId + "], videoUrl = [" + url + "], name = ["
1729+
+ serviceId + "], url = [" + url + "], name = ["
17301730
+ title + "], playQueue = [" + playQueue + "]");
17311731
}
17321732

0 commit comments

Comments
 (0)