[YouTube] Fix regression introduced in the order of streams used when adding more parameters to InnerTube requests, using the iOS client for livestreams and more

This commit is contained in:
TiA4f8R 2022-04-16 19:00:41 +02:00
parent 5f8f3929bd
commit 9f9af35adb
No known key found for this signature in database
GPG key ID: E6D3E7F5949450DD
2 changed files with 136 additions and 8 deletions

View file

@ -60,6 +60,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Pair;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils;
@ -71,7 +72,6 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@ -1170,19 +1170,19 @@ public class YoutubeStreamExtractor extends StreamExtractor {
return urlAndItags;
}
final Map<String, JsonObject> streamingDataAndCpnLoopMap = new HashMap<>();
final List<Pair<JsonObject, String>> streamingDataAndCpnLoopList = new ArrayList<>();
// Use the androidStreamingData object first because there is no n param and no
// signatureCiphers in streaming URLs of the Android client
streamingDataAndCpnLoopMap.put(androidCpn, androidStreamingData);
streamingDataAndCpnLoopMap.put(html5Cpn, html5StreamingData);
streamingDataAndCpnLoopList.add(new Pair<>(androidStreamingData, androidCpn));
streamingDataAndCpnLoopList.add(new Pair<>(html5StreamingData, html5Cpn));
// Use the iosStreamingData object in the last position because most of the available
// streams can be extracted with the Android and web clients and also because the iOS
// client is only enabled by default on livestreams
streamingDataAndCpnLoopMap.put(iosCpn, iosStreamingData);
streamingDataAndCpnLoopList.add(new Pair<>(iosStreamingData, iosCpn));
for (final Map.Entry<String, JsonObject> entry : streamingDataAndCpnLoopMap.entrySet()) {
urlAndItags.putAll(getStreamsFromStreamingDataKey(entry.getValue(), streamingDataKey,
itagTypeWanted, entry.getKey()));
for (final Pair<JsonObject, String> pair : streamingDataAndCpnLoopList) {
urlAndItags.putAll(getStreamsFromStreamingDataKey(pair.getFirst(), streamingDataKey,
itagTypeWanted, pair.getSecond()));
}
return urlAndItags;

View file

@ -0,0 +1,128 @@
package org.schabi.newpipe.extractor.utils;
import java.io.Serializable;
import java.util.Objects;
/**
* Serializable class to create a pair of objects.
*
* <p>
* The two objects of the pair must be {@link Serializable serializable} and can be of the same
* type.
* </p>
*
* <p>
* Note that this class is not intended to be used as a general-purpose pair and should only be
* used when interfacing with the extractor.
* </p>
*
* @param <F> the type of the first object, which must be {@link Serializable}
* @param <S> the type of the second object, which must be {@link Serializable}
*/
public class Pair<F extends Serializable, S extends Serializable> implements Serializable {
/**
* The first object of the pair.
*/
private F firstObject;
/**
* The second object of the pair.
*/
private S secondObject;
/**
* Creates a new {@link Pair} object.
*
* @param first the first object of the pair
* @param second the second object of the pair
*/
public Pair(final F first, final S second) {
firstObject = first;
secondObject = second;
}
/**
* Sets the first object, which must be of the {@link F} type.
*
* @param first the new first object of the pair
*/
public void setFirst(final F first) {
firstObject = first;
}
/**
* Sets the first object, which must be of the {@link S} type.
*
* @param second the new first object of the pair
*/
public void setSecond(final S second) {
secondObject = second;
}
/**
* Gets the first object of the pair.
*
* @return the first object of the pair
*/
public F getFirst() {
return firstObject;
}
/**
* Gets the second object of the pair.
*
* @return the second object of the pair
*/
public S getSecond() {
return this.secondObject;
}
/**
* Returns a string representation of the current {@code Pair}.
*
* <p>
* The string representation will look like this:
* <code>
* {<i>firstObject.toString()</i>, <i>secondObject.toString()</i>}
* </code>
* </p>
*
* @return a string representation of the current {@code Pair}
*/
@Override
public String toString() {
return "{" + firstObject + ", " + secondObject + "}";
}
/**
* Reveals whether an object is equal to this {@code Pair} instance.
*
* @param obj the object to compare with this {@code Pair} instance
* @return whether an object is equal to this {@code Pair} instance
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Pair<?, ?> pair = (Pair<?, ?>) obj;
return Objects.equals(firstObject, pair.firstObject) && Objects.equals(secondObject,
pair.secondObject);
}
/**
* Returns a hash code of the current {@code Pair} by using the first and second object.
*
* @return a hash code of the current {@code Pair}
*/
@Override
public int hashCode() {
return Objects.hash(firstObject, secondObject);
}
}