Merge 4b86db0e8bdd324dc08f92698ccb4d0449f7b676 into 35b70c5e9e8d791ae268bac677a3b760b1b4e8bf

This commit is contained in:
TransZAllen 2026-02-20 12:48:57 +01:00 committed by GitHub
commit 1a5a228220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 170 additions and 0 deletions

View File

@ -31,6 +31,7 @@ import androidx.core.os.BundleCompat;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.extractor.utils.SubtitleDeduplicator;
import java.io.File;
import java.io.FileInputStream;
@ -70,6 +71,8 @@ public final class StateSaver {
if (TextUtils.isEmpty(cacheDirPath)) {
cacheDirPath = context.getCacheDir().getAbsolutePath();
}
SubtitleDeduplicator.setCacheDirPath(cacheDirPath);
}
/**

View File

@ -11,11 +11,15 @@ import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.HttpURLConnection;
import java.nio.channels.ClosedByInterruptException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_FORBIDDEN;
import org.schabi.newpipe.extractor.utils.SubtitleDeduplicator;
public class DownloadInitializer extends Thread {
private static final String TAG = "DownloadInitializer";
@ -46,6 +50,23 @@ public class DownloadInitializer extends Thread {
int retryCount = 0;
int httpCode = 204;
//process local file URI (file://)
for (int i = 0; i < mMission.urls.length && mMission.running; i++) {
String currentUrl = mMission.urls[i];
if (true == islocalSubtitleUri(currentUrl)) {
LocalSubtitleConverter.convertLocalTtmlToVtt(currentUrl, mMission);
// Subtitle download missions always contain exactly one URL.
// Once the local subtitle is converted, the mission is
// considered finished.
// Do not replace this with `continue` unless subtitle missions
// support multiple URLs in the future.
return;
}
}
// process remote, for example: http:// or https://
while (true) {
try {
if (mMission.blocks == null && mMission.current == 0) {
@ -54,6 +75,7 @@ public class DownloadInitializer extends Thread {
long lowestSize = Long.MAX_VALUE;
for (int i = 0; i < mMission.urls.length && mMission.running; i++) {
mConn = mMission.openConnection(mMission.urls[i], true, 0, 0);
mMission.establishConnection(mId, mConn);
dispose();
@ -205,4 +227,34 @@ public class DownloadInitializer extends Thread {
super.interrupt();
if (mConn != null) dispose();
}
private boolean isLocalUri(String url) {
String URL_PREFIX = SubtitleDeduplicator.LOCAL_SUBTITLE_URL_PREFIX;
if (url.startsWith(URL_PREFIX)) {
return true;
} else {
return false;
}
}
private boolean isSubtitleDownloadMission() {
char downloadKind = mMission.kind;
if ('s' == downloadKind) {
return true;
}
return false;
}
private boolean islocalSubtitleUri(String url) {
if (true == isSubtitleDownloadMission()) {
if (true == isLocalUri(url)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,115 @@
package us.shandian.giga.get;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import android.util.Log;
import org.schabi.newpipe.streams.io.SharpStream;
import org.schabi.newpipe.extractor.utils.SubtitleDeduplicator;
final class LocalSubtitleConverter {
private static final String TAG = "LocalSubtitleConverter";
private LocalSubtitleConverter() {
// no instance
}
/**
* Converts a local(file://) TTML subtitle file into VTT format
* and stores it in the user-defined/chosen directory.
*
* @param localSubtitleUri file:// URI of the local TTML subtitle
* @param subtitleMission current download mission, and it is a command
* initiated manually by the user (via a button).
* @return 0 if success, non-zero error code otherwise
*/
public static int convertLocalTtmlToVtt(String localSubtitleUri,
DownloadMission subtitleMission) {
if (!isValidLocalUri(localSubtitleUri)) {
return 1;
}
File ttmlFile = new File(
getAbsolutePathFromLocalUri(localSubtitleUri)
);
if (!ttmlFile.exists()) {
subtitleMission.notifyError(DownloadMission.ERROR_FILE_CREATION, null);
return 2;
}
if (!subtitleMission.storage.canWrite()) {
subtitleMission.notifyError(DownloadMission.ERROR_PERMISSION_DENIED, null);
return 3;
}
writeLocalTtmlAsVtt(ttmlFile, subtitleMission);
printLocalSubtitleConvertedOk(subtitleMission);
return 0;
}
private static boolean isValidLocalUri(String localUri) {
String URL_PREFIX = SubtitleDeduplicator.LOCAL_SUBTITLE_URL_PREFIX;
if (localUri.length() <= URL_PREFIX.length()) {
return false;
}
return true;
}
private static String getAbsolutePathFromLocalUri(String localSubtitleUri) {
String URL_PREFIX = SubtitleDeduplicator.LOCAL_SUBTITLE_URL_PREFIX;
int prefixLength = URL_PREFIX.length();
// Remove URL_PREFIX
String absolutePath = localSubtitleUri.substring(prefixLength);
return absolutePath;
}
private static void writeLocalTtmlAsVtt(File localTtmlFile,
DownloadMission mission) {
try (FileInputStream inputTtmlStream = new FileInputStream(localTtmlFile);
SharpStream outputVttStream = mission.storage.getStream()) {
byte[] buffer = new byte[DownloadMission.BUFFER_SIZE];
int bytesRead;
long totalBytes = 0;
while ((bytesRead = inputTtmlStream.read(buffer)) != -1) {
outputVttStream.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
mission.notifyProgress(bytesRead);
}
mission.length = totalBytes;
mission.unknownLength = false;
mission.notifyFinished();
} catch (IOException e) {
String logMessage = "Error extracting subtitle paragraphs from " +
localTtmlFile.getAbsolutePath() + ", error:" +
e.getMessage();
Log.e(TAG, logMessage);
mission.notifyError(DownloadMission.ERROR_FILE_CREATION, e);
}
}
private static void printLocalSubtitleConvertedOk(DownloadMission mission) {
try {
String logMessage = "Local subtitle uri is extracted to:" +
mission.storage.getName();
Log.i(TAG, logMessage);
} catch (NullPointerException e) {
Log.w(TAG, "Fail to convert ttml subtitle to vtt.", e);
}
}
}