package me.kavin.piped.utils; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.kavin.piped.utils.obj.*; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.linkhandler.ReadyChannelTabListLinkHandler; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamType; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import static me.kavin.piped.utils.URLUtils.*; public class CollectionUtils { public static Streams collectStreamInfo(StreamInfo info) { final List subtitles = new ObjectArrayList<>(); final List chapters = new ObjectArrayList<>(); info.getStreamSegments().forEach(segment -> chapters.add(new ChapterSegment(segment.getTitle(), rewriteURL(segment.getPreviewUrl()), segment.getStartTimeSeconds()))); final List previewFrames = new ObjectArrayList<>(); info.getPreviewFrames().forEach(frame -> previewFrames.add(new PreviewFrames(frame.getUrls().stream().map(URLUtils::rewriteURL).toList(), frame.getFrameWidth(), frame.getFrameHeight(), frame.getTotalCount(), frame.getDurationPerFrame(), frame.getFramesPerPageX(), frame.getFramesPerPageY()))); info.getSubtitles() .forEach(subtitle -> subtitles.add(new Subtitle(rewriteURL(subtitle.getContent()), subtitle.getFormat().getMimeType(), subtitle.getDisplayLanguageName(), subtitle.getLanguageTag(), subtitle.isAutoGenerated()))); final List videoStreams = new ObjectArrayList<>(); final List audioStreams = new ObjectArrayList<>(); boolean livestream = info.getStreamType() == StreamType.LIVE_STREAM; final Map extraParams = Map.of( // "ump", "1", // "srfvp", "1" ); if (!livestream) { info.getVideoOnlyStreams().forEach(stream -> videoStreams.add(new PipedStream(stream.getItag(), rewriteVideoURL(stream.getContent(), extraParams), String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType(), true, stream.getBitrate(), stream.getInitStart(), stream.getInitEnd(), stream.getIndexStart(), stream.getIndexEnd(), stream.getCodec(), stream.getWidth(), stream.getHeight(), stream.getFps(), stream.getItagItem().getContentLength()))); info.getVideoStreams() .forEach(stream -> videoStreams .add(new PipedStream(stream.getItag(), rewriteVideoURL(stream.getContent(), Map.of()), String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType(), false, stream.getItagItem().getContentLength()))); info.getAudioStreams() .forEach(stream -> audioStreams.add(new PipedStream(stream.getItag(), rewriteVideoURL(stream.getContent(), extraParams), String.valueOf(stream.getFormat()), stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType(), false, stream.getBitrate(), stream.getInitStart(), stream.getInitEnd(), stream.getIndexStart(), stream.getIndexEnd(), stream.getItagItem().getContentLength(), stream.getCodec(), stream.getAudioTrackId(), stream.getAudioTrackName(), Optional.ofNullable(stream.getAudioTrackType()).map(Enum::name).orElse(null), Optional.ofNullable(stream.getAudioLocale()).map(Locale::toLanguageTag).orElse(null) ))); } final List relatedStreams = collectRelatedItems(info.getRelatedItems()); final List metaInfo = new ObjectArrayList<>(); info.getMetaInfo().forEach(metaInfoItem -> metaInfo.add(new MetaInfo(metaInfoItem.getTitle(), metaInfoItem.getContent().getContent(), metaInfoItem.getUrls(), metaInfoItem.getUrlTexts() ))); return new Streams(info.getName(), info.getDescription().getContent(), info.getTextualUploadDate(), info.getUploaderName(), substringYouTube(info.getUploaderUrl()), getLastThumbnail(info.getUploaderAvatars()), getLastThumbnail(info.getThumbnails()), info.getDuration(), info.getViewCount(), info.getLikeCount(), info.getDislikeCount(), info.getUploaderSubscriberCount(), info.isUploaderVerified(), audioStreams, videoStreams, relatedStreams, subtitles, livestream, rewriteVideoURL(info.getHlsUrl(), Map.of()), rewriteVideoURL(info.getDashMpdUrl(), Map.of()), null, info.getCategory(), info.getLicence(), info.getPrivacy().name().toLowerCase(), info.getTags(), metaInfo, chapters, previewFrames); } public static List collectRelatedItems(List items) { return items .stream() .parallel() .map(item -> { if (item instanceof StreamInfoItem) { return collectRelatedStream(item); } else if (item instanceof PlaylistInfoItem) { return collectRelatedPlaylist(item); } else if (item instanceof ChannelInfoItem) { return collectRelatedChannel(item); } else { throw new RuntimeException( "Unknown item type: " + item.getClass().getName()); } }).toList(); } private static StreamItem collectRelatedStream(Object o) { StreamInfoItem item = (StreamInfoItem) o; return new StreamItem(substringYouTube(item.getUrl()), item.getName(), getLastThumbnail(item.getThumbnails()), item.getUploaderName(), substringYouTube(item.getUploaderUrl()), getLastThumbnail(item.getUploaderAvatars()), item.getTextualUploadDate(), item.getShortDescription(), item.getDuration(), item.getViewCount(), item.getUploadDate() != null ? item.getUploadDate().offsetDateTime().toInstant().toEpochMilli() : -1, item.isUploaderVerified(), item.isShortFormContent()); } private static PlaylistItem collectRelatedPlaylist(Object o) { PlaylistInfoItem item = (PlaylistInfoItem) o; return new PlaylistItem(substringYouTube(item.getUrl()), item.getName(), getLastThumbnail(item.getThumbnails()), item.getUploaderName(), substringYouTube(item.getUploaderUrl()), item.isUploaderVerified(), item.getPlaylistType().name(), item.getStreamCount()); } private static ChannelItem collectRelatedChannel(Object o) { ChannelInfoItem item = (ChannelInfoItem) o; return new ChannelItem(substringYouTube(item.getUrl()), item.getName(), getLastThumbnail(item.getThumbnails()), item.getDescription(), item.getSubscriberCount(), item.getStreamCount(), item.isVerified()); } public static List collectPreloadedTabs(List tabs) { return tabs .stream() .filter(ReadyChannelTabListLinkHandler.class::isInstance) .map(ReadyChannelTabListLinkHandler.class::cast) .toList(); } }