Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
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;

Expand All @@ -71,7 +72,6 @@
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;
Expand Down Expand Up @@ -1170,19 +1170,19 @@ private Map<String, ItagItem> getItags(@Nonnull final String streamingDataKey,
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;
Expand Down
128 changes: 128 additions & 0 deletions extractor/src/main/java/org/schabi/newpipe/extractor/utils/Pair.java
Original file line number Diff line number Diff line change
@@ -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);
}
}