A minimalist GTK3 video player using GStreamer for playback, featuring a floating controls interface, playlist management, and session persistence via SQLite.
- Floating Controls: Ultra-minimalist interface with controls that appear on hover
- Playlist Management: Add files, directories, shuffle, and repeat modes
- Session Persistence: Automatically saves and restores last playlist
- Keyboard Shortcuts: Space (play/pause), F/F11 (fullscreen), arrows (seek/volume)
- Drag & Drop: Drop video files directly onto the window
- Multi-format Support: MP4, MKV, AVI, MOV, WEBM, and many more
- Python 3
- GTK3
- GStreamer 1.0 + GStreamer Python bindings
- SQLite3 (built-in)
# Run with Python module
python -m mados_video_player
# Or use the executable
./mados-video-player
# Or run directly
python __main__.pyβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VideoPlayerApp β
β βββββββββββββββ βββββββββββββββ ββββββββββββββββββββ β
β β Overlay β β Video β β Floating β β
β β Container β β Display β β Controls β β
β βββββββββββββββ βββββββββββββββ ββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PlaylistWindow β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β TreeView with playlist items β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β player.py - GStreamer Engine β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PlayerEngine: play, pause, stop, seek, volume β β
β β Video sink detection (Wayland/X11/GTK) β β
β β Callbacks: on_eos, on_error, on_state, on_positionβ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β playlist.py - Playlist Management β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Playlist: add_file, add_directory, next, previous β β
β β Repeat modes: NONE, ALL, ONE β β
β β Shuffle support β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β database.py - SQLite Persistence β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PlaylistDB: save/load playlists, session state β β
β β Tables: playlists, playlist_items, session β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
sequenceDiagram
participant User
participant UI as VideoPlayerApp
participant Engine as PlayerEngine
participant Playlist as Playlist
participant Display as Video Display
User->>UI: Double-click / Play button
UI->>Playlist: get current file
Playlist-->>UI: filepath
UI->>Engine: load(filepath)
Engine->>Engine: Set GStreamer URI
Engine-->>UI: True (loaded)
UI->>Engine: play()
Engine->>Display: Start video output
Engine->>UI: on_state("playing")
UI->>UI: Update play button to βΈ
loop Playback
Engine->>UI: on_position(ns)
UI->>UI: Update seek slider
end
Engine->>UI: on_eos()
UI->>Playlist: next()
Playlist-->>UI: next filepath
UI->>Engine: load(filepath)
UI->>Engine: play()
sequenceDiagram
participant User
participant UI as VideoPlayerApp
participant Window as PlaylistWindow
participant Playlist as Playlist
participant DB as PlaylistDB
User->>UI: Menu > Playlist
UI->>Window: Create PlaylistWindow
Window->>Playlist: _refresh()
Playlist-->>Window: items list
Window->>Window: Populate TreeView
User->>Window: Double-click item
Window->>Playlist: select(index)
Playlist-->>Window: filepath
Window->>UI: _play_current()
UI->>UI: Engine.load() + play()
User->>Window: Click delete
Window->>Playlist: remove(index)
Playlist-->>Window: updated items
Window->>Window: _refresh()
Window->>DB: save_session_playlist()
sequenceDiagram
participant UI
participant Engine as PlayerEngine
participant Gst as GStreamer
participant Pipeline as Pipeline
UI->>UI: _on_seek_changed()
UI->>UI: _do_debounced_seek(50ms debounce)
UI->>Engine: seek(position_ns)
alt Pipeline not ready
Engine->>Pipeline: set_state(PAUSED)
end
Engine->>Pipeline: seek(speed, TIME, FLUSH, SET, position)
Pipeline-->>Engine: seek result
Engine-->>UI: Return
Note over Engine,Pipeline: If was playing, stay playing<br/>If was paused, stay paused
sequenceDiagram
participant App
participant Playlist as Playlist
participant DB as PlaylistDB
participant SQLite as SQLite DB
Note over App,SQLite: On Startup (restore_session)
App->>DB: load_session_playlist()
DB->>SQLite: Query session + playlist
SQLite-->>DB: Session data
DB-->>App: {filepaths, current_index, repeat_mode, shuffle}
App->>Playlist: items.extend(filepaths)
App->>Playlist: current_index = ...
App->>Playlist: repeat_mode = ...
Note over App,SQLite: On Close (_on_destroy)
App->>Playlist: get current state
App->>DB: save_session_playlist(filepaths, index, repeat, shuffle)
DB->>SQLite: INSERT/UPDATE playlists + session
SQLite-->>DB: Success
DB-->>App: Return
sequenceDiagram
participant Engine as PlayerEngine
participant Gst as GStreamer
participant Display as Gdk.Display
Engine->>Engine: _setup_pipeline()
Engine->>Gst: ElementFactory.make("playbin")
alt gtksink available (preferred)
Engine->>Gst: ElementFactory.make("gtksink")
Engine->>Engine: Use gtksink widget
else Wayland display
Engine->>Display: get_default()
Display-->>Engine: WaylandDisplay
Engine->>Gst: Try gtkglsink, then waylandsink
else X11 display
Engine->>Display: get_default()
Display-->>Engine: X11Display
Engine->>Gst: Try xvimagesink, fallback to ximagesink
else Other
Engine->>Gst: Use autovideosink
end
Engine->>Gst: pipeline.set_property("video-sink", sink)
Engine->>Gst: bus.add_signal_watch()
Engine->>Engine: Connect bus callbacks
| Key | Action |
|---|---|
| Space | Play/Pause |
| F / F11 | Toggle Fullscreen |
| Escape | Exit Fullscreen |
| Left/Right | Seek -10s / +10s (Ctrl for 60s) |
| Up/Down | Volume Β±5% |
| M | Toggle Mute |
| N | Next track |
| P | Previous track |
| Ctrl+O | Open file |
| Ctrl+Q | Quit |
mados-video-player/
βββ __init__.py # Package metadata
βββ __main__.py # Entry point
βββ app.py # Main window (GTK)
βββ player.py # GStreamer engine
βββ playlist.py # Playlist logic
βββ database.py # SQLite persistence
βββ theme.py # Nord CSS theme
βββ translations.py # i18n strings
βββ .gitignore
βββ AGENTS.md # Developer guidelines
βββ README.md
MIT License