pair) {
+ final var keyValue = pair.first.toUpperCase() + "=" + pair.second.trim();
+
+ final var bytes = keyValue.getBytes();
+ final var buf = ByteBuffer.allocate(4 + bytes.length);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(bytes.length);
+ buf.put(bytes);
+ return buf.array();
+ }
+
+ /**
+ * This returns a complete "OpusTags" header, created from the provided metadata tags.
+ *
+ * You probably want to use makeOpusMetadata(), which uses this function to create
+ * a header with sensible metadata filled in.
+ *
+ * @param keyValueLines A list of pairs of the tags. This can also be though of as a mapping
+ * from one key to multiple values.
+ * @return The binary header
+ */
+ private static byte[] makeOpusTagsHeader(final List> keyValueLines) {
+ final var tags = keyValueLines
+ .stream()
+ .filter(p -> !p.second.isBlank())
+ .map(OggFromWebMWriter::makeOpusMetadataTag)
+ .collect(Collectors.toUnmodifiableList());
+
+ final var tagsBytes = tags.stream().collect(Collectors.summingInt(arr -> arr.length));
+
+ // Fixed header fields + dynamic fields
+ final var byteCount = 16 + tagsBytes;
+
+ final var head = ByteBuffer.allocate(byteCount);
+ head.order(ByteOrder.LITTLE_ENDIAN);
+ head.put(new byte[]{
+ 0x4F, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73, // "OpusTags" binary string
+ 0x00, 0x00, 0x00, 0x00, // vendor (aka. Encoder) string of length 0
+ });
+ head.putInt(tags.size()); // 4 bytes for tag count
+ tags.forEach(head::put); // dynamic amount of tag bytes
+
+ return head.array();
+ }
+
private void write(final ByteBuffer buffer) throws IOException {
output.write(buffer.array(), 0, buffer.position());
buffer.position(0);
diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
index ea41f3e81..409fcb30c 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
@@ -806,7 +806,7 @@ public final class ListHelper {
final Locale preferredLanguage = Localization.getPreferredLocale(context);
final boolean preferOriginalAudio =
preferences.getBoolean(context.getString(R.string.prefer_original_audio_key),
- false);
+ true);
final boolean preferDescriptiveAudio =
preferences.getBoolean(context.getString(R.string.prefer_descriptive_audio_key),
false);
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java b/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
index dc46ced5d..badb5f7ed 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
@@ -34,7 +34,7 @@ class OggFromWebmDemuxer extends Postprocessing {
@Override
int process(SharpStream out, @NonNull SharpStream... sources) throws IOException {
- OggFromWebMWriter demuxer = new OggFromWebMWriter(sources[0], out);
+ OggFromWebMWriter demuxer = new OggFromWebMWriter(sources[0], out, streamInfo);
demuxer.parseSource();
demuxer.selectTrack(0);
demuxer.build();
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
index 7f5c85d27..1c9143252 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
@@ -4,6 +4,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
+import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.streams.io.SharpStream;
import java.io.File;
@@ -30,7 +31,8 @@ public abstract class Postprocessing implements Serializable {
public transient static final String ALGORITHM_M4A_NO_DASH = "mp4D-m4a";
public transient static final String ALGORITHM_OGG_FROM_WEBM_DEMUXER = "webm-ogg-d";
- public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[] args) {
+ public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[] args,
+ StreamInfo streamInfo) {
Postprocessing instance;
switch (algorithmName) {
@@ -56,6 +58,7 @@ public abstract class Postprocessing implements Serializable {
}
instance.args = args;
+ instance.streamInfo = streamInfo;
return instance;
}
@@ -75,8 +78,8 @@ public abstract class Postprocessing implements Serializable {
*/
private final String name;
-
private String[] args;
+ protected StreamInfo streamInfo;
private transient DownloadMission mission;
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
index 45211211f..76da18b2d 100755
--- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
@@ -40,6 +40,7 @@ import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import org.schabi.newpipe.download.DownloadActivity;
+import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
@@ -74,12 +75,12 @@ public class DownloadManagerService extends Service {
private static final String EXTRA_THREADS = "DownloadManagerService.extra.threads";
private static final String EXTRA_POSTPROCESSING_NAME = "DownloadManagerService.extra.postprocessingName";
private static final String EXTRA_POSTPROCESSING_ARGS = "DownloadManagerService.extra.postprocessingArgs";
- private static final String EXTRA_SOURCE = "DownloadManagerService.extra.source";
private static final String EXTRA_NEAR_LENGTH = "DownloadManagerService.extra.nearLength";
private static final String EXTRA_PATH = "DownloadManagerService.extra.storagePath";
private static final String EXTRA_PARENT_PATH = "DownloadManagerService.extra.storageParentPath";
private static final String EXTRA_STORAGE_TAG = "DownloadManagerService.extra.storageTag";
private static final String EXTRA_RECOVERY_INFO = "DownloadManagerService.extra.recoveryInfo";
+ private static final String EXTRA_STREAM_INFO = "DownloadManagerService.extra.streamInfo";
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
@@ -353,13 +354,13 @@ public class DownloadManagerService extends Service {
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
* @param threads the number of threads maximal used to download chunks of the file.
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
- * @param source source url of the resource
+ * @param streamInfo stream metadata that may be written into the downloaded file.
* @param psArgs the arguments for the post-processing algorithm.
* @param nearLength the approximated final length of the file
* @param recoveryInfo array of MissionRecoveryInfo, in case is required recover the download
*/
public static void startMission(Context context, String[] urls, StoredFileHelper storage,
- char kind, int threads, String source, String psName,
+ char kind, int threads, StreamInfo streamInfo, String psName,
String[] psArgs, long nearLength,
ArrayList recoveryInfo) {
final Intent intent = new Intent(context, DownloadManagerService.class)
@@ -367,14 +368,14 @@ public class DownloadManagerService extends Service {
.putExtra(EXTRA_URLS, urls)
.putExtra(EXTRA_KIND, kind)
.putExtra(EXTRA_THREADS, threads)
- .putExtra(EXTRA_SOURCE, source)
.putExtra(EXTRA_POSTPROCESSING_NAME, psName)
.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs)
.putExtra(EXTRA_NEAR_LENGTH, nearLength)
.putExtra(EXTRA_RECOVERY_INFO, recoveryInfo)
.putExtra(EXTRA_PARENT_PATH, storage.getParentUri())
.putExtra(EXTRA_PATH, storage.getUri())
- .putExtra(EXTRA_STORAGE_TAG, storage.getTag());
+ .putExtra(EXTRA_STORAGE_TAG, storage.getTag())
+ .putExtra(EXTRA_STREAM_INFO, streamInfo);
context.startService(intent);
}
@@ -387,9 +388,9 @@ public class DownloadManagerService extends Service {
char kind = intent.getCharExtra(EXTRA_KIND, '?');
String psName = intent.getStringExtra(EXTRA_POSTPROCESSING_NAME);
String[] psArgs = intent.getStringArrayExtra(EXTRA_POSTPROCESSING_ARGS);
- String source = intent.getStringExtra(EXTRA_SOURCE);
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
String tag = intent.getStringExtra(EXTRA_STORAGE_TAG);
+ StreamInfo streamInfo = (StreamInfo)intent.getSerializableExtra(EXTRA_STREAM_INFO);
final var recovery = IntentCompat.getParcelableArrayListExtra(intent, EXTRA_RECOVERY_INFO,
MissionRecoveryInfo.class);
Objects.requireNonNull(recovery);
@@ -405,11 +406,11 @@ public class DownloadManagerService extends Service {
if (psName == null)
ps = null;
else
- ps = Postprocessing.getAlgorithm(psName, psArgs);
+ ps = Postprocessing.getAlgorithm(psName, psArgs, streamInfo);
final DownloadMission mission = new DownloadMission(urls, storage, kind, ps);
mission.threadCount = threads;
- mission.source = source;
+ mission.source = streamInfo.getUrl();
mission.nearLength = nearLength;
mission.recoveryInfo = recovery.toArray(new MissionRecoveryInfo[0]);
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index 727ce4df4..6e8e2979b 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -62,7 +62,7 @@
app:useSimpleSummaryProvider="true" />
= 23