Skip to content

RU RU 2 Managing links

J-RAP edited this page Nov 7, 2026 · 3 revisions

2. РАБОТА СО ССЫЛКАМИ

Note

Настраивается: platforms.allowMatureContent, searchLimit, searchCleanupInterval, biliBiliCookie и player.mrlCleanupInterval. Смотрите их комментарии в config/watermedia.toml.

MRL (Multimedia Resource Location) превращает любую ссылку в медиа, которое она содержит: один или несколько источников, у каждого свои варианты качества, аудиодорожки и метаданные. Он разрешается в фоне и остаётся в кэше.

2.1 РАЗРЕШЕНИЕ ССЫЛОК

MRL mrl = PlayerAPI.mrl("https://example.com/movie.mp4");    // A WEB LINK, A FILE UNDER THE WORKING DIRECTORY OR A water:// LINK
MRL[] queue = PlayerAPI.preload(firstUri, secondUri);        // START RESOLVING SEVERAL AT ONCE

// FROM A GAME TICK OR A UI TIMER
switch (mrl.status()) {
    case FETCHING -> { }                                     // STILL RESOLVING
    case LOADED -> play(mrl);                                // READY TO PLAY
    case BLOCKED -> showMatureWarning();                     // MATURE CONTENT WHILE IT'S NOT ALLOWED
    case ERROR -> showError(mrl.exception());                // WHY IT FAILED; A MALFORMED LINK STARTS HERE
    case EXPIRED, FORGOTTEN -> mrl = mrl.reload();           // STALE OR EVICTED: KEEP THE HANDLE reload() RETURNS
}

mrl.subscribe(done -> refreshUi());                          // OR GET CALLED ONCE WHEN IT FINISHES OR FAILS
boolean finished = mrl.await(5_000);                         // OR WAIT, BUT NEVER ON THE GAME OR RENDER THREAD
// ONE LINK CAN HOLD SEVERAL SOURCES, SUCH AS A GALLERY WITH AN IMAGE AT 0 AND A VIDEO AT 1
MRL.Source first = mrl.source(0);                            // null FOR A WRONG INDEX
MRL.Source video = mrl.sourceByType(MediaType.VIDEO);        // THE FIRST VIDEO, OR null
List<MRL.Source> all = mrl.sources();

MediaType type = video.type();                               // IMAGE, VIDEO, AUDIO...
Metadata info = video.metadata();                            // TITLE, DESCRIPTION, AUTHOR, DURATION...
URI thumbnail = video.thumbnail();
URI link = video.uri(MediaQuality.HIGH);                     // THE CLOSEST QUALITY AVAILABLE
List<Track> dubs = video.audioTracks();                      // SEPARATE AUDIO TRACKS, THE ORIGINAL FIRST

MediaPlayer player = PlayerAPI.player(mrl, 1, gfx, sfx);     // PLAY THE SOURCE AT INDEX 1 (SEE PLAYING MEDIA)

Прямая ссылка завершается ошибкой, если сервер отвечает статусом ошибки или ответом без медиа; плейлисты HLS открываются как одно видео, а плейлисты IPTV как один источник на канал.

2.2 ПЛАТФОРМЫ

Ссылки с этих платформ разрешаются из коробки:

  • 📺 YouTube, Twitch, Kick, BiliBili, Odysee, D.tube, VidLii
  • 🐦 Twitter (X), Bluesky, TikTok, Facebook, Instagram
  • 🎵 SoundCloud, Newgrounds (фильмы, музыка и арт)
  • 🖼️ Imgur, Lightshot, Medal, Streamable, Sendvid
  • 📁 Google Drive, Dropbox, MediaFire
  • 🔞 PornHub (только при включённом platforms.allowMatureContent)
  • 🔗 Прямые ссылки на любое видео, музыку, изображение или плейлист, локальные файлы и ссылки water://

YouTube, SoundCloud, Facebook и Instagram воспроизводятся через yt-dlp, которому нужен Binaries. BiliBili воспроизводится до 480p или до 1080p (8K с VIP) с cookie вашей сессии в platforms.biliBiliCookie.

Platform.Resolution resolved = PlatformAPI.fetch(uri);       // THE RESOLUTION WITHOUT AN MRL, FOR TOOLS; null WHEN NO PLATFORM HANDLES THE LINK

// YOUR OWN SITE: CHECKED BEFORE THE BUILT-IN PLATFORMS, AND IT NEEDS NO STARTUP
PlatformAPI.register(new Platform() {
    @Override
    public String name() { return "MySite"; }

    @Override
    public Platform.Resolution resolve(final URI uri) throws PlatformException {
        if (!"mysite.com".equals(uri.getHost())) return null;            // NOT YOURS: THE NEXT PLATFORM TRIES
        if (isProfile(uri)) throw PlatformException.unsupported(this.name(), uri); // YOURS BUT NOTHING TO PLAY: MRL GOES ERROR
        if (isMature(uri)) throw new MatureContentException(this.name(), "Mature video"); // MRL GOES BLOCKED

        final Platform.Quality quality = new Platform.Quality(findVideo(uri), 1920, 1080); // REAL SIZE, 0 WHEN UNKNOWN
        final Platform.Source source = new Platform.Source(MediaType.VIDEO, null, null, null, List.of(quality), null, null);
        return new Platform.Resolution(null, source);                    // null EXPIRY: THE LINKS NEVER EXPIRE
    }
});

Любая другая ошибка вашей платформы тоже оформляется как PlatformException, а альбом или плейлист пропускает плохой элемент, а не падает целиком.

2.3 ПОИСК

YouTube (с Binaries), Twitch, Kick и Imgur поддерживают поиск по ключевым словам, а ваша платформа присоединяется к ним, если переопределит search(query, limit).

List<PlatformResult> results = PlatformAPI.search("lofi");   // RETURNS AT ONCE; THE LIST FILLS AS PLATFORMS ANSWER
boolean searching = PlatformAPI.searching("lofi");           // false ONCE EVERY PLATFORM ANSWERED; POLL BOTH FROM THE UI
for (final PlatformResult hit: results) {
    show(hit.title(), hit.thumbnail(), hit.platform().name()); // WHEN PICKED, PlayerAPI.mrl(hit.uri()) OPENS IT LIKE ANY LINK
}
List<PlatformResult> fresh = PlatformAPI.search("lofi", true); // ASK THE PLATFORMS AGAIN INSTEAD OF THE CACHE

Новый запрос заменяет предыдущий, а пока пользователь продолжает печатать, запрос немного ждёт следующего нажатия клавиши. Twitch и Kick показывают только каналы в прямом эфире.

2.4 ПРОТОКОЛ WATER

PlayerAPI.mrl("water://local/config/song.mp3");              // ./config/song.mp3, RESOLVED AGAINST THE WORKING DIRECTORY
PlayerAPI.mrl("water://remote/xyz12345");                    // A FILE ON YOUR FILE SERVER (SEE UPLOADING AND DOWNLOADING FILES)
PlayerAPI.mrl("water://global/abcd6789");                    // A FILE ON OUR GLOBAL SERVER

Ссылки remote и global содержат ID файла, выданный сервером, а не путь к папке.

2.5 ДОВЕРИЕ HTTPS И УЧЁТНЫЕ ДАННЫЕ

HTTPS работает из коробки с сертификатами, которым Java уже доверяет, и эта проверка никогда не отключается.

Используете самоподписанный сертификат или собственный центр сертификации? Импортируйте его в truststore и укажите этот truststore Java до запуска WATERMeDIA (в Minecraft добавьте те же опции -D в аргументы JVM лаунчера):

keytool -importcert -alias my-server -file my-server.crt -keystore my-truststore.jks -storepass changeit -noprompt
java -Djavax.net.ssl.trustStore=my-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -jar my-app.jar
  • Пустой или повреждённый truststore не даёт FFmpeg запуститься, поэтому видео остаётся выключенным, пока его не исправят.
  • Собственной сборке FFmpeg нужна такая же поддержка TLS, как у встроенной.
  • Заголовки входа и cookie (Authorization, Cookie, X-WaterMedia-Token) никогда не уходят вслед за редиректом на другой сервер, а редиректы ведут только на ссылки http или https.

Clone this wiki locally