Skip to content

Add Stream / Copy stream link (seekable preview without downloading) - #34

Open
kapshytar wants to merge 6 commits into
Aldeshov:masterfrom
kapshytar:feature/stream-context-menu
Open

Add Stream / Copy stream link (seekable preview without downloading)#34
kapshytar wants to merge 6 commits into
Aldeshov:masterfrom
kapshytar:feature/stream-context-menu

Conversation

@kapshytar

Copy link
Copy Markdown

What

Adds Stream and Copy stream link to the file right-click menu, so you can preview a video straight from the device without downloading it.

Why

To check a large video you currently have to download the whole file first. This lets you open it instantly and seek to any point — only the watched bytes are fetched, nothing is saved to disk.

How

New services/stream_server.py starts a tiny ThreadingHTTPServer on 127.0.0.1:<random port> serving one remote file with full HTTP Range support (206 Partial Content, Content-Range, Accept-Ranges: bytes). Each range is read on demand with the already-used external-adb primitive:

adb -s <serial> exec-out "tail -c +<start+1> '<path>' | head -c <len>"

shlex.quote is applied to the remote path (spaces work), one reusable server is kept per (device, path), and client disconnects/seeks are handled quietly (the adb subprocess is killed). Standard library only.

Context-menu wiring in gui/explorer/files.py: Stream opens the URL via webbrowser.open (browsers play mp4 with a seek bar); Copy stream link copies it to the clipboard for VLC/QuickTime. Shown only for files, not directories.

Tested manually against a device: a Range: bytes=1000000-1001000 request returned 206 with the correct Content-Range and bytes matching a direct adb read.

kapshytar and others added 6 commits June 27, 2026 01:39
Right-clicking a file now offers 'Stream' and 'Copy stream link'. Both
spin up a tiny localhost HTTP server (services/stream_server.py) that
serves that one remote file with full HTTP Range support, reading bytes
on demand via 'adb exec-out tail|head' — so a player can SEEK without
downloading the whole file and nothing is written to disk. 'Stream' opens
the URL in the default browser (plays mp4 with a seek bar); 'Copy stream
link' puts the URL on the clipboard for VLC/QuickTime. Paths with spaces
are shlex-quoted; one reusable server per file.
adb pull only prints its [ N%] progress to a TTY; when its output is
piped (as the app does) it stays silent until the transfer finishes, so
UpDownHelper never received any progress lines and the download bar sat
at 'Waiting... 0%' the whole time.

Query the remote file size up front (via stat, space-safe through
shlex.join) and poll the size of the file being written locally on a
background thread, emitting progress to the existing callback. A 60 MB
pull now reports 5..100% instead of nothing.
…й клик по видео=стрим, индикатор канала, авто-connect
…NULL, таймауты в StorageRepository/stream_server, _TransportWorker lifecycle, симлинк-папка не стримится, эпоха превью, shlex.quote путь, пути скриптов в configurations
Здесь лежала независимая копия всего Range/adb HTTP-сервера (~200 строк). Она
разошлась с оригиналом: не получила фикс «имя файла с расширением в URL стрима»
(QuickTime отваливался с err -11828), отдавала любой файл как video/mp4, и текла —
реестр хранил URL, но не сам сервер, а shutdown() не звался нигде, так что каждая
скопированная ссылка оставляла слушающий сокет до выхода из приложения.

Ядро теперь одно — adb_stream.py в общей папке скриптов (его же гоняет
phone-stream.sh из трея). Здесь осталось только своё: реестр по (device, path)
и закрытие серверов в closeEvent. 215 строк → 74.

Проверено на телефоне: URL несёт имя с расширением, повторный запрос того же
файла переиспользует сервер, разные файлы получают разные порты, range-probe.sh
14 PASS/0 FAIL, после stop_all оба порта закрыты.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant