private FormatWithUrl loadBestFormatWithUrl(HttpInterface httpInterface) throws Exception { JsonBrowser info = getTrackInfo(httpInterface); String playerScript = extractPlayerScriptFromInfo(info); List<YoutubeTrackFormat> formats = loadTrackFormats(info, httpInterface, playerScript); YoutubeTrackFormat format = findBestSupportedFormat(formats); URI signedUrl = sourceManager.getCipherManager().getValidUrl(httpInterface, playerScript, format); return new FormatWithUrl(format, signedUrl); }
private static boolean isBetterFormat(YoutubeTrackFormat format, YoutubeTrackFormat other) { YoutubeFormatInfo info = format.getInfo(); if (info == null) { return false; } else if (other == null) { return true; } else if (info.ordinal() != other.getInfo().ordinal()) { return info.ordinal() < other.getInfo().ordinal(); } else { return format.getBitrate() > other.getBitrate(); } }
private AudioItem loadLinkedPlaylistWithId(String playlistId, String videoId) { AudioPlaylist playlist = loadPlaylistWithId(playlistId, videoId); if (playlist == null) { return loadTrackWithVideoId(videoId, false); } else { return playlist; } }
@Override public AudioSourceManager newSourceManagerInstance() throws Exception { YoutubeAudioSourceManager manager = new YoutubeAudioSourceManager(); manager.setPlaylistPageCount(100); return manager; } }
@Override public void process(LocalAudioTrackExecutor localExecutor) throws Exception { try (HttpInterface httpInterface = sourceManager.getHttpInterface()) { FormatWithUrl format = loadBestFormatWithUrl(httpInterface); log.debug("Starting track from URL: {}", format.signedUrl); if (trackInfo.isStream) { processStream(localExecutor, format); } else { processStatic(localExecutor, httpInterface, format); } } }
private void processStream(LocalAudioTrackExecutor localExecutor, FormatWithUrl format) throws Exception { if (MIME_AUDIO_WEBM.equals(format.details.getType().getMimeType())) { throw new FriendlyException("YouTube WebM streams are currently not supported.", COMMON, null); } else { try (HttpInterface streamingInterface = sourceManager.getHttpInterface()) { processDelegate(new YoutubeMpegStreamAudioTrack(trackInfo, streamingInterface, format.signedUrl), localExecutor); } } }
private void processStatic(LocalAudioTrackExecutor localExecutor, HttpInterface httpInterface, FormatWithUrl format) throws Exception { try (YoutubePersistentHttpStream stream = new YoutubePersistentHttpStream(httpInterface, format.signedUrl, format.details.getContentLength())) { if (format.details.getType().getMimeType().endsWith("/webm")) { processDelegate(new MatroskaAudioTrack(trackInfo, stream), localExecutor); } else { processDelegate(new MpegAudioTrack(trackInfo, stream), localExecutor); } } }
/** * Create an instance. * @param allowSearch Whether to allow search queries as identifiers */ public YoutubeAudioSourceManager(boolean allowSearch) { signatureCipherManager = new YoutubeSignatureCipherManager(); httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager(); this.allowSearch = allowSearch; playlistPageCount = 6; searchProvider = new YoutubeSearchProvider(this); mixProvider = new YoutubeMixProvider(this); }
private JsonBrowser getTrackInfo(HttpInterface httpInterface) throws Exception { return sourceManager.getTrackInfoFromMainPage(httpInterface, getIdentifier(), true); }
private AudioItem loadItemOnce(AudioReference reference) { if (allowSearch && reference.identifier.startsWith(SEARCH_PREFIX)) { return searchProvider.loadSearchResult(reference.identifier.substring(SEARCH_PREFIX.length()).trim()); } return loadNonSearch(reference.identifier); }
private void execute(LocalAudioTrackExecutor localExecutor) throws InterruptedException { TrackState state = new TrackState(signedUrl); try { while (!state.finished) { processNextSegment(localExecutor, state); state.relativeSequence++; } } finally { if (state.trackConsumer != null) { state.trackConsumer.close(); } } }
/** * @param videoId Video ID. Used as {@link AudioTrackInfo#identifier}. * @param title See {@link AudioTrackInfo#title}. * @param uploader Name of the uploader. Used as {@link AudioTrackInfo#author}. * @param isStream See {@link AudioTrackInfo#isStream}. * @param duration See {@link AudioTrackInfo#length}. * @return An audio track instance. */ public YoutubeAudioTrack buildTrackObject(String videoId, String title, String uploader, boolean isStream, long duration) { return new YoutubeAudioTrack(new AudioTrackInfo(title, uploader, duration, videoId, isStream, getWatchUrl(videoId)), this); }
private JsonBrowser getTrackInfoFromEmbedPage(HttpInterface httpInterface, String videoId) throws IOException { JsonBrowser basicInfo = loadTrackBaseInfoFromEmbedPage(httpInterface, videoId); basicInfo.put("args", loadTrackArgsFromVideoInfoPage(httpInterface, videoId, basicInfo.get("sts").text())); return basicInfo; }
@Override public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) { return new YoutubeAudioTrack(trackInfo, this); }
/** * @param maximumPoolSize Maximum number of threads in mix loader thread pool. */ public void setMixLoaderMaximumPoolSize(int maximumPoolSize) { mixProvider.setLoaderMaximumPoolSize(maximumPoolSize); }
@Override public void configureBuilder(Consumer<HttpClientBuilder> configurator) { httpInterfaceManager.configureBuilder(configurator); searchProvider.configureBuilder(configurator); }
@Override public AudioSourceManager newSourceManagerInstance() throws Exception { YoutubeAudioSourceManager manager = new YoutubeAudioSourceManager(); manager.setPlaylistPageCount(100); return manager; } }
@Override public AudioTrack makeClone() { return new YoutubeAudioTrack(trackInfo, sourceManager); }
@Override public AudioSourceManager newSourceManagerInstance() throws Exception { YoutubeAudioSourceManager manager = new YoutubeAudioSourceManager(); manager.setPlaylistPageCount(100); return manager; } }
@Override public AudioSourceManager newSourceManagerInstance() throws Exception { YoutubeAudioSourceManager manager = new YoutubeAudioSourceManager(); manager.setPlaylistPageCount(100); return manager; } }