#!/bin/sh # --- Configuration --- scripts_dir="${XDG_SCRIPTS_HOME:-${HOME}/.local/bin}" db_path="$HOME/.local/share/history/mpv.sqlite" playlist_dir="$HOME/.config/mpv/playlists" mpv_opts="--x11-name=video" ytdl_format="bestvideo[height<=1080]+bestaudio/best[height<=1080]" # Managed mount points: "mountpoint|mount_cmd|unmount_cmd" (one per line) MANAGED_MOUNTS="$HOME/Secret|$scripts_dir/ecrypt|$scripts_dir/ecrypt /mnt/second|$scripts_dir/mounter|$scripts_dir/unmounter" # Video file extensions for find commands VIDEO_EXTS='-iname "*.mp4" -o -iname "*.mkv" -o -iname "*.mov" -o -iname "*.flv" -o -iname "*.wmv" -o -iname "*.webm" -o -iname "*.mpeg" -o -iname "*.mpg" -o -iname "*.avi" -o -iname "*.ts" -o -iname "*.3gp" -o -iname "*.rmvb"' # --- Utility Functions --- find_videos() { eval "find \"$1\" -maxdepth 1 -type f \\( $VIDEO_EXTS \\)" | sort -V } has_videos() { eval "find \"$1\" -maxdepth 1 -type f \\( $VIDEO_EXTS \\) -print -quit" | grep -q . } is_mounted() { findmnt "$1" >/dev/null 2>&1; } # Return the managed mount point for a given file path get_managed_mount() { while IFS='|' read -r mp mcmd ucmd; do [ -n "$mp" ] && echo "$1" | grep -q "^$mp/" && echo "$mp" && return 0 done </dev/null 2>&1; then notify-send "Playing video from URL:" "$url" play --ytdl-format="$ytdl_format" "$url" else loginurl fi } # --- Local File Playback --- play_media() { _path="" for _a in "$@"; do case "$_a" in --*) ;; *) _path="$_a" ;; esac done _mp=$(get_managed_mount "$_path") if [ -n "$_mp" ]; then mount_path "$_path" play "$@" && unmount_path "$_mp" || exit else play "$@" || exit fi } play_playlist() { # Check if playlist references any managed mount path _mp="" while IFS='|' read -r mp mcmd ucmd; do [ -n "$mp" ] && grep -q "$mp/" "$1" 2>/dev/null && _mp="$mp" && break done <"$tmplist" play_playlist "$tmplist" rm -f "$tmplist" } list_and_play() { dir="$1" has_videos "$dir" || { echo "No video files in $dir." && exit; } choice=$(printf "List files\nEnter filenames" | dmenu -i -p "Choose an option:") case "$choice" in "Enter filenames") search_term=$(echo | dmenu -i -p "File names:") [ -z "$search_term" ] && exit notify-send "Finding videos named with '$search_term'.." files=$(eval "find \"$dir\" -type f \\( $VIDEO_EXTS \\) -iname \"*$search_term*\"" | sort -V) [ -z "$files" ] && echo "No files named with \"$search_term\"." && exit tmpplaylist=$(mktemp /tmp/mpv_playlist_XXXXXX.m3u) echo "$files" >"$tmpplaylist" play_playlist "$tmpplaylist" rm -f "$tmpplaylist" ;; "List files") files_with_paths=$(find_videos "$dir") selected_file=$(printf "All\n%s" "$files_with_paths" | sed 's|.*/||' | dmenu -i -l 21 -p "Select a file:") [ -z "$selected_file" ] && exit [ "$selected_file" = "All" ] && make_tmp_playlist "$dir" && return full_path=$(echo "$files_with_paths" | grep -F "$selected_file") [ -f "$full_path" ] && play_media "$full_path" && return ;; esac } # --- Directory Browser --- list_nonempty_subdirs() { find "$1" -mindepth 1 -maxdepth 1 -type d ! -name ".*" 2>/dev/null | while read -r d; do [ -n "$(ls -A "$d" 2>/dev/null)" ] && echo "$d" done } browse_local() { dir_list="$HOME/Downloads $HOME/Torrents/complete $HOME/Videos" # Add managed mount points (always shown, even if not yet mounted) while IFS='|' read -r mp mcmd ucmd; do [ -n "$mp" ] && [ -d "$mp" ] && dir_list="$dir_list $mp" done <&2 exit 1 } history=$( sqlite3 "$db_path" <<'SQL' WITH LatestFiles AS ( SELECT path, title, time_pos, MAX(date) AS max_date FROM loaded_items GROUP BY path ), FormattedHistory AS ( SELECT path, title, CASE WHEN time_pos IS NOT NULL THEN printf('%02d:%02d:%02d', time_pos / 3600, (time_pos % 3600) / 60, time_pos % 60) ELSE '00:00:00' END AS formatted_time, max_date FROM LatestFiles ) SELECT path || ' | ' || title || ' | ' || formatted_time FROM FormattedHistory ORDER BY max_date DESC; SQL ) [ -z "$history" ] && { echo "No history items found." >&2 exit 1 } temp_file=$(mktemp) echo "$history" | while IFS= read -r line; do file_path=$(printf '%s\n' "$line" | awk -F ' \\| ' '{print $1}') [ -f "$file_path" ] && printf '%s\n' "$line" >>"$temp_file" done [ -s "$temp_file" ] || { echo "No valid history items (all files missing)." >&2 rm -f "$temp_file" exit 1 } chosen=$(dmenu -i -l 20 -p "Choose a file to play:" <"$temp_file") rm -f "$temp_file" [ -z "$chosen" ] && exit file_path=$(printf '%s\n' "$chosen" | awk -F ' \\| ' '{print $1}') formatted_time=$(printf '%s\n' "$chosen" | awk -F ' \\| ' '{print $3}') time_pos=$(printf '%s\n' "$formatted_time" | awk -F: '{print ($1 * 3600) + ($2 * 60) + $3}') if [ "$time_pos" -gt 0 ]; then play_media --start="$time_pos" "$file_path" else play_media "$file_path" fi } # --- Main --- trap 'unmount_all; exit' EXIT INT content_choice=$(printf "URL\nLocal Files\nPlaylist\nHistory" | dmenu -i -p "Choose media source:") case "$content_choice" in "URL") play_url ;; "Local Files") browse_local ;; "Playlist") choose_playlist ;; "History") history_play ;; *) exit ;; esac