pull/1106/merge
Isira Seneviratne 2025-04-10 13:08:55 +02:00 zatwierdzone przez GitHub
commit 24c63a7781
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
21 zmienionych plików z 94 dodań i 80 usunięć

Wyświetl plik

@ -11,7 +11,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.util.List;
import static org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampExtractorHelper.BASE_URL;
@ -26,13 +26,14 @@ public class BandcampRadioInfoItemExtractor implements StreamInfoItemExtractor {
show = radioShow;
}
@Nonnull
@Override
public long getDuration() {
public Duration getDurationObject() {
/* Duration is only present in the more detailed information that has to be queried
separately. Therefore, over 300 queries would be needed every time the kiosk is opened if we
were to display the real value. */
//return query(show.getInt("id")).getLong("audio_duration");
return 0;
//return Duration.ofSeconds(query(show.getInt("id")).getLong("audio_duration"));
return Duration.ZERO;
}
@Nullable

Wyświetl plik

@ -43,9 +43,4 @@ public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInf
public List<Image> getThumbnails() throws ParsingException {
return getImagesFromImageId(discograph.getLong("art_id"), true);
}
@Override
public long getDuration() {
return -1;
}
}

Wyświetl plik

@ -11,6 +11,7 @@ import org.schabi.newpipe.extractor.stream.StreamExtractor;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
@ -51,9 +52,10 @@ public class BandcampPlaylistStreamInfoItemExtractor extends BandcampStreamInfoI
}
}
@Nonnull
@Override
public long getDuration() {
return track.getLong("duration");
public Duration getDurationObject() {
return Duration.ofSeconds(track.getLong("duration"));
}
@Override

Wyświetl plik

@ -47,9 +47,4 @@ public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoIte
public List<Image> getThumbnails() throws ParsingException {
return getImagesFromSearchResult(searchResult);
}
@Override
public long getDuration() {
return -1;
}
}

Wyświetl plik

@ -60,11 +60,6 @@ public class MediaCCCLiveStreamKioskExtractor implements StreamInfoItemExtractor
return false;
}
@Override
public long getDuration() throws ParsingException {
return 0;
}
@Override
public long getViewCount() throws ParsingException {
return -1;

Wyświetl plik

@ -64,7 +64,7 @@ public class MediaCCCRecentKiosk extends KioskExtractor<StreamInfoItem> {
.map(JsonObject.class::cast)
.map(MediaCCCRecentKioskExtractor::new)
// #813 / voc/voctoweb#609 -> returns faulty data -> filter it out
.filter(extractor -> extractor.getDuration() > 0)
.filter(extractor -> !extractor.getDurationObject().isZero())
.forEach(collector::commit);
return new InfoItemsPage<>(collector, null);

Wyświetl plik

@ -9,6 +9,7 @@ import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConfe
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
@ -53,10 +54,11 @@ public class MediaCCCRecentKioskExtractor implements StreamInfoItemExtractor {
}
@Override
public long getDuration() {
@Nonnull
public Duration getDurationObject() {
// duration and length have the same value, see
// https://github.com/voc/voctoweb/blob/master/app/views/public/shared/_event.json.jbuilder
return event.getInt("duration");
return Duration.ofSeconds(event.getLong("duration"));
}
@Override

Wyświetl plik

@ -10,6 +10,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.util.List;
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getThumbnailsFromStreamItem;
@ -32,8 +33,9 @@ public class MediaCCCStreamInfoItemExtractor implements StreamInfoItemExtractor
}
@Override
public long getDuration() {
return event.getInt("length");
@Nonnull
public Duration getDurationObject() {
return Duration.ofSeconds(event.getLong("length"));
}
@Override

Wyświetl plik

@ -10,6 +10,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.List;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.getAvatarsFromOwnerAccountOrVideoChannelObject;
@ -100,8 +101,9 @@ public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor
}
@Override
public long getDuration() {
return item.getLong("duration");
@Nonnull
public Duration getDurationObject() {
return Duration.ofSeconds(item.getLong("duration"));
}
protected void setBaseUrl(final String baseUrl) {

Wyświetl plik

@ -9,6 +9,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;
import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.List;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAllImagesFromArtworkOrAvatarUrl;
@ -35,8 +36,9 @@ public class SoundcloudStreamInfoItemExtractor implements StreamInfoItemExtracto
}
@Override
public long getDuration() {
return itemObject.getLong("duration") / 1000L;
@Nonnull
public Duration getDurationObject() {
return Duration.ofMillis(itemObject.getLong("duration"));
}
@Override

Wyświetl plik

@ -44,8 +44,8 @@ import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;
import com.grack.nanojson.JsonWriter;
import org.jsoup.nodes.Entities;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.Image.ResolutionLevel;
import org.schabi.newpipe.extractor.downloader.Response;
@ -67,10 +67,12 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -240,21 +242,22 @@ public final class YoutubeParsingHelper {
* @return the duration in seconds
* @throws ParsingException when more than 3 separators are found
*/
public static int parseDurationString(@Nonnull final String input)
throws ParsingException, NumberFormatException {
public static Duration parseDurationString(@Nonnull final String input)
throws ParsingException {
// If time separator : is not detected, try . instead
final String[] splitInput = input.contains(":")
? input.split(":")
: input.split("\\.");
final int[] units = {24, 60, 60, 1};
final int offset = units.length - splitInput.length;
final var units = List.of(ChronoUnit.DAYS, ChronoUnit.HOURS, ChronoUnit.MINUTES,
ChronoUnit.SECONDS);
final int offset = units.size() - splitInput.length;
if (offset < 0) {
throw new ParsingException("Error duration string with unknown format: " + input);
}
int duration = 0;
Duration duration = Duration.ZERO;
for (int i = 0; i < splitInput.length; i++) {
duration = units[i + offset] * (duration + convertDurationToInt(splitInput[i]));
duration = duration.plus(convertDurationToInt(splitInput[i]), units.get(i + offset));
}
return duration;
}
@ -271,11 +274,7 @@ public final class YoutubeParsingHelper {
* @return The converted integer or 0 if the conversion failed.
*/
private static int convertDurationToInt(final String input) {
if (input == null || input.isEmpty()) {
return 0;
}
final String clearedInput = Utils.removeNonDigitCharacters(input);
final String clearedInput = input != null ? Utils.removeNonDigitCharacters(input) : "";
try {
return Integer.parseInt(clearedInput);
} catch (final NumberFormatException ex) {

Wyświetl plik

@ -33,12 +33,6 @@ public class YoutubeFeedInfoItemExtractor implements StreamInfoItemExtractor {
return false;
}
@Override
public long getDuration() {
// Not available when fetching through the feed endpoint.
return -1;
}
@Override
public long getViewCount() {
return Long.parseLong(entryElement.getElementsByTag("media:statistics").first()

Wyświetl plik

@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.List;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
@ -67,7 +68,8 @@ public class YoutubeMusicSongOrVideoInfoItemExtractor implements StreamInfoItemE
}
@Override
public long getDuration() throws ParsingException {
@Nonnull
public Duration getDurationObject() throws ParsingException {
final String duration = descriptionElements.getObject(descriptionElements.size() - 1)
.getString("text");
if (!isNullOrEmpty(duration)) {

Wyświetl plik

@ -5,7 +5,6 @@ import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.DateWrapper;
@ -96,11 +95,6 @@ public class YoutubeReelInfoItemExtractor implements StreamInfoItemExtractor {
return false;
}
@Override
public long getDuration() throws ParsingException {
return -1;
}
@Override
public String getUploaderName() throws ParsingException {
return null;

Wyświetl plik

@ -41,7 +41,7 @@ import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
@ -136,10 +136,11 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
throw new ParsingException("Could not get name");
}
@Nonnull
@Override
public long getDuration() throws ParsingException {
public Duration getDurationObject() throws ParsingException {
if (getStreamType() == StreamType.LIVE_STREAM) {
return -1;
return Duration.ZERO;
}
String duration = getTextFromObject(videoInfo.getObject("lengthText"));
@ -169,7 +170,7 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
if (isPremiere()) {
// Premieres can be livestreams, so the duration is not available in this
// case
return -1;
return Duration.ZERO;
}
throw new ParsingException("Could not get duration");

Wyświetl plik

@ -26,6 +26,7 @@ import org.schabi.newpipe.extractor.localization.DateWrapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.util.List;
/**
@ -40,7 +41,8 @@ public class StreamInfoItem extends InfoItem {
@Nullable
private DateWrapper uploadDate;
private long viewCount = -1;
private long duration = -1;
@Nonnull
private Duration duration = Duration.ZERO;
private String uploaderUrl = null;
@Nonnull
@ -76,12 +78,21 @@ public class StreamInfoItem extends InfoItem {
this.viewCount = viewCount;
}
public long getDuration() {
@Nonnull
public Duration getDurationObject() {
return duration;
}
public void setDurationObject(@Nonnull final Duration durationObject) {
this.duration = durationObject;
}
public long getDuration() {
return duration.toSeconds();
}
public void setDuration(final long duration) {
this.duration = duration;
this.duration = Duration.ofSeconds(duration);
}
public String getUploaderUrl() {

Wyświetl plik

@ -27,6 +27,7 @@ import org.schabi.newpipe.extractor.localization.DateWrapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.util.List;
public interface StreamInfoItemExtractor extends InfoItemExtractor {
@ -48,12 +49,25 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
boolean isAd() throws ParsingException;
/**
* Get the stream duration in seconds
* Get the stream duration as a {@link Duration}.
*
* @return the stream duration in seconds or -1 if no duration is available
* @return the stream duration in seconds or {@link Duration#ZERO} if no duration is available
* @throws ParsingException if there is an error in the extraction
*/
long getDuration() throws ParsingException;
@Nonnull
default Duration getDurationObject() throws ParsingException {
return Duration.ZERO;
}
/**
* Get the stream duration in seconds.
*
* @return the stream duration in seconds or 0 if no duration is available
* @throws ParsingException if there is an error in the extraction
*/
default long getDuration() throws ParsingException {
return getDurationObject().toSeconds();
}
/**
* Parses the number of views

Wyświetl plik

@ -44,12 +44,12 @@ public class StreamInfoItemsCollector
throw new FoundAdException("Found ad");
}
final StreamInfoItem resultItem = new StreamInfoItem(
getServiceId(), extractor.getUrl(), extractor.getName(), extractor.getStreamType());
final var resultItem = new StreamInfoItem(getServiceId(), extractor.getUrl(),
extractor.getName(), extractor.getStreamType());
// optional information
try {
resultItem.setDuration(extractor.getDuration());
resultItem.setDurationObject(extractor.getDurationObject());
} catch (final Exception e) {
addError(e);
}

Wyświetl plik

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -99,12 +100,9 @@ public class ExtractorAsserts {
assertGreater(expected, actual, actual + " is not > " + expected);
}
public static void assertGreater(
final long expected,
final long actual,
final String message
) {
assertTrue(actual > expected, message);
public static <T extends Comparable<T>> void assertGreater(final T expected, final T actual,
final String message) {
assertTrue(actual.compareTo(expected) > 0, message);
}
public static void assertGreaterOrEqual(final long expected, final long actual) {

Wyświetl plik

@ -14,6 +14,7 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import java.time.Duration;
import java.util.List;
import java.util.stream.Stream;
@ -41,9 +42,9 @@ public class MediaCCCRecentListExtractorTest {
isNullOrEmpty(item.getName()),
"Name=[" + item.getName() + "] of " + item + " is empty or null"
),
() -> assertGreater(0,
item.getDuration(),
"Duration[=" + item.getDuration() + "] of " + item + " is <= 0"
() -> assertGreater(Duration.ZERO,
item.getDurationObject(),
"Duration[=" + item.getDurationObject() + "] of " + item + " is <= 0"
)
);
}

Wyświetl plik

@ -9,6 +9,7 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.stream.AudioTrackType;
import java.io.IOException;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -38,9 +39,12 @@ public class YoutubeParsingHelperTest {
@Test
void testParseDurationString() throws ParsingException {
assertEquals(1162567, YoutubeParsingHelper.parseDurationString("12:34:56:07"));
assertEquals(4445767, YoutubeParsingHelper.parseDurationString("1,234:56:07"));
assertEquals(754, YoutubeParsingHelper.parseDurationString("12:34 "));
assertEquals(Duration.ofDays(12).plusHours(34).plusMinutes(56).plusSeconds(7),
YoutubeParsingHelper.parseDurationString("12:34:56:07"));
assertEquals(Duration.ofHours(1234).plusMinutes(56).plusSeconds(7),
YoutubeParsingHelper.parseDurationString("1,234:56:07"));
assertEquals(Duration.ofMinutes(12).plusSeconds(34),
YoutubeParsingHelper.parseDurationString("12:34 "));
}
@Test