Add Makefile for user-scoped install, as well as DEVLOG
This commit is contained in:
parent
b8127aa167
commit
2fc129ec21
4 changed files with 144 additions and 0 deletions
75
DEVLOG.md
Normal file
75
DEVLOG.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Development Log
|
||||
|
||||
This file records the app's architecture and the implementation choices made
|
||||
to improve startup and queue responsiveness. It describes intended behavior;
|
||||
no formal performance benchmark has been run.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `mpvremote/config.py` is the central settings module. It defines the mpv IPC
|
||||
socket path, supported video extensions, key bindings, app version, and media
|
||||
directory. The media directory defaults to `~/Videos`; an override is read
|
||||
from `~/.config/mpvremotemedia` and can be edited in Settings.
|
||||
- `mpvremote/mpv_client.py` sends JSON commands to mpv over its Unix-domain IPC
|
||||
socket and decodes JSON responses.
|
||||
- `mpvremote/views.py` contains the curses views:
|
||||
- `MainView` provides playback controls and status.
|
||||
- `PlaylistView` displays and edits mpv's current playlist.
|
||||
- `QueueView` searches the configured media library and queues files.
|
||||
- `SettingsView` edits the media-directory setting.
|
||||
- `AboutView` displays app information and key bindings.
|
||||
- `mpvremote/app.py` initializes curses, constructs the views, owns the media
|
||||
cache and scan worker, and coordinates drawing and input in the application
|
||||
loop.
|
||||
- `mpvremote/__init__.py` exports `App` and `SOCKET`. Running
|
||||
`python3 -m mpvremote` loads the package and enters `mpvremote/__main__.py`.
|
||||
The entry point handles `--help`, checks that the configured socket exists,
|
||||
then uses `curses.wrapper` to set up and restore the terminal. The app enables
|
||||
keypad mode and handles input through its `getch()` loop.
|
||||
|
||||
## Startup and media scanning
|
||||
|
||||
The initial recursive media scan runs on a background worker instead of
|
||||
blocking `App` initialization. The worker scans immediately and waits 120
|
||||
seconds between subsequent scans. An event marks completion of the first scan.
|
||||
If Queue is opened before that scan completes, it displays a scanning message
|
||||
and populates automatically when the scan publishes its results.
|
||||
|
||||
The scan commits an immutable tuple of entries containing the display name,
|
||||
absolute path, and a pre-normalized `casefold()` name. Cache replacement and
|
||||
version increments happen under a lock. `get_videos_with_version()` returns
|
||||
the snapshot and version together; `get_videos()` retains the simpler
|
||||
`(name, path)` interface for other callers.
|
||||
|
||||
## Responsiveness changes
|
||||
|
||||
### Escape-key decoding
|
||||
|
||||
After curses initializes, the app requests a 50 ms Escape-sequence delay using
|
||||
`curses.set_escdelay()`, when the platform supports it. This reduces the wait
|
||||
when Escape is pressed while retaining a short interval for distinguishing
|
||||
Escape from terminal key sequences such as arrows.
|
||||
|
||||
### Queue filtering and rendering
|
||||
|
||||
`QueueView` caches its indexed media snapshot and filtered results. Filtering
|
||||
runs only when the search query or media-cache version changes; rendering does
|
||||
not rescan or refilter the list. While Queue is active, the event loop uses a
|
||||
100 ms input timeout and calls the view's update hook, allowing completed
|
||||
background scans to appear without requiring a keypress. Other views continue
|
||||
to wait for input normally.
|
||||
|
||||
## User-level installation
|
||||
|
||||
The root `Makefile` provides `install`, `verify`, and `uninstall` targets.
|
||||
Installation copies the package beneath `~/.local/share/mpvremote` and creates
|
||||
an executable `~/.local/bin/mpvremote` wrapper that sets `PYTHONPATH` and runs
|
||||
`python3 -m mpvremote`. It does not edit shell startup files; it prints a PATH
|
||||
instruction when needed. The verification target runs the installed launcher
|
||||
with `--help`, which does not require mpv to be running.
|
||||
|
||||
## Known performance limits
|
||||
|
||||
The main view still retrieves playback status properties synchronously through
|
||||
mpv IPC. Those requests have not been batched or moved to a background poller;
|
||||
they remain a possible area for future profiling and optimization.
|
||||
37
Makefile
Normal file
37
Makefile
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
PREFIX ?= $(HOME)/.local
|
||||
PYTHON ?= python3
|
||||
|
||||
SHARE_DIR := $(PREFIX)/share
|
||||
APP_DIR := $(SHARE_DIR)/mpvremote
|
||||
BIN_DIR := $(PREFIX)/bin
|
||||
LAUNCHER := $(BIN_DIR)/mpvremote
|
||||
|
||||
.PHONY: help install uninstall verify
|
||||
|
||||
help:
|
||||
@echo "make install Install mpvremote under $(PREFIX)"
|
||||
@echo "make verify Check the installed launcher and module"
|
||||
@echo "make uninstall Remove the user-level installation"
|
||||
|
||||
install:
|
||||
install -d "$(APP_DIR)" "$(BIN_DIR)"
|
||||
cp -R mpvremote/. "$(APP_DIR)/"
|
||||
@printf '%s\n' \
|
||||
'#!/bin/sh' \
|
||||
'export PYTHONPATH="$(SHARE_DIR)$${PYTHONPATH:+:$$PYTHONPATH}"' \
|
||||
'exec "$(PYTHON)" -m mpvremote "$$@"' \
|
||||
> "$(LAUNCHER)"
|
||||
chmod 755 "$(LAUNCHER)"
|
||||
@case ":$$PATH:" in \
|
||||
*":$(BIN_DIR):"*) echo "$(BIN_DIR) is already in PATH" ;; \
|
||||
*) echo 'Add $(BIN_DIR) to PATH: export PATH="$(BIN_DIR):$$PATH"' ;; \
|
||||
esac
|
||||
|
||||
verify:
|
||||
test -d "$(APP_DIR)"
|
||||
test -x "$(LAUNCHER)"
|
||||
cd "$(HOME)" && "$(LAUNCHER)" --help
|
||||
|
||||
uninstall:
|
||||
rm -f "$(LAUNCHER)"
|
||||
rm -rf "$(APP_DIR)"
|
||||
25
README.md
25
README.md
|
|
@ -51,6 +51,31 @@ cd mpvremote
|
|||
python3 -m mpvremote
|
||||
```
|
||||
|
||||
### Install for your user
|
||||
|
||||
Install a launcher and module copy under `~/.local` without root privileges:
|
||||
|
||||
```bash
|
||||
make install
|
||||
```
|
||||
|
||||
If `~/.local/bin` is not already on your `PATH`, add this line to your shell
|
||||
startup file (for example, `~/.bashrc`) and open a new shell:
|
||||
|
||||
```bash
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
Verify the installation and print command-line usage with:
|
||||
|
||||
```bash
|
||||
make verify
|
||||
mpvremote --help
|
||||
```
|
||||
|
||||
Remove the user-level installation with `make uninstall`. Set `PREFIX` to
|
||||
install under a different directory.
|
||||
|
||||
## Configuration
|
||||
|
||||
The IPC socket and video extensions are set in `mpvremote/config.py`. The media
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import curses
|
||||
|
|
@ -7,6 +8,12 @@ from mpvremote.config import SOCKET
|
|||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="mpvremote",
|
||||
description="A curses-based remote control for a running mpv player.",
|
||||
)
|
||||
parser.parse_args()
|
||||
|
||||
if not os.path.exists(SOCKET):
|
||||
print(f"Error: Socket {SOCKET} not found or mpv is not running.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue