Сохранение таймкода воспроизведения на стороне Торсервера - #818
Open
s1mptom wants to merge 7 commits into
Open
Conversation
added 7 commits
July 26, 2026 22:07
On reader close, save the on-screen position (read head minus the client's buffer) into the viewed record as a 0..1 byte-fraction of the file. Duration-free (no ffprobe): consumers multiply by media runtime. Gated by new BTSets fields SavePosition / BufferSizeMB / AutoBuffer; a preload/probe (read < buffer) is skipped. Reader gains startOffset (first Range-seek target) for future auto-buffer measurement.
TorrServer now records where playback actually was, so a position survives the player never reporting back - a TV powering off, an app being killed, or an external player that has no callback. While a stream runs and when it ends, the position is taken as the read head minus the client's buffer and stored in the viewed data in seconds, using the file's real duration from ffprobe (which the feature requires, and which the installers now offer to install). Offset, length and duration are stored alongside so clients can show progress without guessing the runtime. The client buffer is measured from how the player loads data: it fills as fast as it can, then settles to the playback rate, and the difference is the buffer. A configured size is used when that measurement is not available. Verified against a simulated player: within ~1.2s of the true on-screen position. Probes, preloads and short requests are ignored, and our own ffprobe stream is marked so probing can never recurse into itself. Marking a file as viewed no longer clears a stored position.
…able The buffer measurement now reports what it derived and from what (fill size and duration, measured playback rate), so the value can be reviewed after a session. The fallback size stays editable while automatic measurement is on, since it is what gets used until the measurement becomes available - roughly the first minute of playback. It is labelled as the fallback in that state.
…t sooner The buffer log was emitted for every stream, including the many short probe and preload requests that never reach the save, which buried the useful lines. It is now written where the value is actually used. The steady playback phase needed before the buffer can be derived drops from 60s to 30s: real sessions were ending before the measurement became available and falling back to the configured size.
Unexport setDuration and probeMarker, which are only used inside the torr package. Rename durationKey to fileKey, since both caches are keyed by it. Name the fallback buffer constant instead of repeating a literal, and report saving under the same [Position] prefix as the buffer measurement. Also drop the unreachable tail of ListViewed, which go vet flags in the file this branch rewrites, and rebuild the web assets with the locked dependency versions.
…rthy The playback rate is multiplied by the fill duration, so an error in the rate grows with however long filling took. A slow line fills slowly, which made the estimate noisy exactly where it is least affordable. The steady phase now has to last at least as long as the fill did, and never less than the previous 30s. Until then the configured size is used.
Filling was declared over at the first pause longer than two seconds, but a client tops its buffer up in bursts, so pauses are normal, and a brief network hiccup while filling looks exactly like one. That ended the measurement early and understated the buffer, which moves the saved position forward - past content the viewer had not reached. The buffer is how far the reader runs ahead of playback, so it is now taken as the largest such lead across sampled positions: bytes read beyond the start, minus what playback consumed in the same time. A hiccup simply is not the maximum, and neither is the low point of a top-up cycle. Playback speed comes from the tail of the session and is only trusted once two consecutive windows agree, which is what separates filling from playing at its own pace. Verified against a simulated player reporting its true on-screen position: within 1.5s of it.
Contributor
|
I don't think you need a plugin for TrackTimecode anymore. The Lampa already supports that natively: yumata/lampa-source#367 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Дисклеймер: код честно навайбкожен (как и описание далее и плагин для лампы). Решал свою давнюю боль (и успешно решил). Буду рад если данный механизм появится в апстриме (мердж ПР или кто-то решит переписать под схожую или более правильную логику)
Сохранение позиции воспроизведения
Внешний плеер, который закрылся штатно, сообщает, где остановился. Тот, который не закрылся —
телевизор выключился на паузе, Android убил приложение — не сообщает ничего, и позиция
теряется. Больнее всего на сериалах: серию потом приходится искать заново.
Здесь позиция записывается на стороне сервера, из того, что и так видно по ридеру.
Включается в Настройках → сохранять позицию воспроизведения. Нужен
ffprobe:установщики предлагают его поставить, а без него переключатель заблокирован с пояснением.
Включить достаточно одну галку.
TrackTimecode— флаг хранения таймкодов, доступный толькочерез API, — подразумевается автоматически, второй настройки искать не нужно.
Что и когда записывается
Пока файл отдаётся, ридер знает смещение в байтах, до которого он выдал данные клиенту. Это
не то место, где находится зритель: плееру отдано всё, что лежит у него в буфере, а смотрит
он позади конца этого буфера.
Смещение переводится в секунды по длительности файла — за этим и нужен
ffprobe. Результаткладётся в запись просмотра каждые 30 секунд и ещё раз при завершении потока.
От мусора в записи защищают три условия:
а не «почти концу» — иначе такое кино предлагалось бы продолжить.
Время меряется двумя способами, берётся большее. Как долго клиент держал поток, зависит от
управления потоком TCP; протяжённость реальных чтений — от того, как быстро торрент отдаёт
данные. Каждая величина по отдельности способна обмануть.
ffprobeспрашивается о файле один раз и не чаще, чем раз в десять минут, по одному процессуза раз. Он читает через тот же самый эндпоинт отдачи, поэтому его собственный запрос несёт
пометку, исключающую его из всего вышеописанного. Без этого замер запускал бы замер.
Как меряется буфер
Чтобы вычесть буфер, его надо знать, но не все плееры о нём не сообщают (или позволяют его настраивать). Зато за ним можно
понаблюдать.
Плеер набивает буфер настолько быстро, насколько позволяет сеть, а затем переходит к
запросам примерно с той скоростью, с какой потребляет данные. Значит на достаточно длинном
отрезке ридер движется со скоростью воспроизведения, а величина, на которую он опережает
зрителя, и есть буфер:
Скорость берётся с хвоста сессии, усредняется по 30-секундным окнам и принимается только
когда два соседних окна сходятся в пределах 40%. Иначе торрент, который подвис и потом
нагнал, был бы прочитан как медленный плеер.
Оценка идёт в дело лишь после того, как воспроизведение наблюдалось не меньше времени, чем
набирался отрыв: до этого отрыв неотличим от первоначального наполнения буфера. Результат
ограничен диапазоном от 4 МБ до 1 ГБ.
Замер против Vimu на 4K-ремуксе: 115 МБ при 100 МБ, выставленных в самом плеере — разница
это то, что плеер держит сверх собственной настройки.
Автозамер — отдельный переключатель, по умолчанию выключен. Когда он выключен или пока ему
не хватает данных, берётся заданное запасное значение (32 МБ, если не менять).
Плагин для Lampa
Вторая половина для пользователей Lampa: сервер хранит
позицию, плагин возвращает её в интерфейс.
https://github.com/s1mptom/lampa-ts-resume
Прямая ссылка для добавления в Lampa (Настройки → Плагины → по ссылке):
Плагин обращается только к тому адресу TorrServer, который уже прописан в настройках Lampa,
и ничего больше не требует.
Пара деталей, объясняющих, почему он вообще понадобился. Открытие торрента не поднимает в
Lampa активити — это модалка, — поэтому плагин цепляется к
Torserver.files(hash), черезкоторую проходят все пути в список файлов. И записывает он два ключа таймлайна: карточка
хеширует серию по оригинальному названию сериала, а список файлов торрента — по
оригинальному заголовку, и правка одного оставляет второй протухшим. Выглядит это как
полоска прогресса, которая сдвинулась на одном экране и не сдвинулась на другом.