lefteros_by SomniusX
EN ↗Πες ένα γεια

1 Νοεμβρίου 2025 / Lefteris Iliadis (SomniusX)

Bash | playyt: Εναλλακτική του yeetube για το terminal

1 Νοεμβρίου 2025

Έχεις ακούσει για το yeetube του thanosapollo; Είναι ένα Emacs package που σου επιτρέπει να αναπαράγεις YouTube βίντεο με mpv και yt-dlp απευθείας από το Emacs. Το πρόβλημα είναι ό

playyt: Το yeetube για το terminal (χωρίς Emacs)

Έχεις ακούσει για το yeetube του thanosapollo; Είναι ένα Emacs package που σου επιτρέπει να αναπαράγεις YouTube βίντεο με mpv και yt-dlp απευθείας από το Emacs. Το πρόβλημα είναι ότι αν δεν χρησιμοποιείς Emacs, δεν μπορείς να το χρησιμοποιήσεις.

Επειδή ήθελα να έχω την ίδια λειτουργικότητα χωρίς να χρειάζεται Emacs, έφτιαξα ένα bash script που κάνει ακριβώς αυτό που κάνει το yeetube, αλλά απευθείας από το terminal. Το λέω playyt.

edit: 2025-11-01 16:30 προσθήκη ascii video player και αλλαγή του άρθρου..

Τι κάνει

Το playyt είναι ένα bash script που παίρνει ένα YouTube URL (ή οποιοδήποτε URL που υποστηρίζει το yt-dlp) και το αναπαράγει με mpv ή ffplay. Ίδια λειτουργικότητα με το yeetube, αλλά χωρίς Emacs. Απλά τρέχεις μια εντολή στο terminal και παίζει το βίντεο.

Η βασική ιδέα είναι να μην χρειάζεται να ανοίγεις browser για να δεις YouTube βίντεο. Μπορείς να δώσεις ένα URL στο terminal και να παίξει απευθείας, ή ακόμα και να κάνεις αναζήτηση και να παίξεις το πρώτο αποτέλεσμα.

Πως λειτουργεί

Η βασική χρήση είναι απλούστατη:

playyt "https://www.youtube.com/watch?v=XXXX"

Αν θες να χρησιμοποιήσεις ffplay αντί για mpv:

playyt "https://www.youtube.com/watch?v=XXXX" ffplay

Αν δεν θες να ανοίξεις browser για να βρεις το URL, μπορείς να κάνεις αναζήτηση απευθείας:

playyt --search "linux tutorial"

Το script θα βρει το πρώτο αποτέλεσμα και θα το παίξει αυτόματα.

ASCII Video Mode

Ένα από τα πιο ενδιαφέρον features είναι η δυνατότητα να δεις τα βίντεο ως ASCII art απευθείας στο terminal. Αυτό είναι χρήσιμο αν θέλεις να μην ανοίγεις κανένα window ή αν απλά θες να δεις πως φαίνεται.

playyt "https://www.youtube.com/watch?v=XXXX" ascii

Το script θα ψάξει αυτόματα για διαθέσιμο ASCII player. Υποστηρίζει:

  • mplayer με caca support (συνήθως το πιο διαθέσιμο)
  • mpv με caca support
  • vtap (Python-based, εύκολο να το βάλεις με pip install vtap)
  • tplay (Rust-based)

Αν δεν βρει κάποιο, θα σου δώσει ακριβείς οδηγίες πως να το εγκαταστήσεις. Το vtap είναι συνήθως η πιο εύκολη επιλογή αν δεν έχεις ήδη mplayer:

pip install --user vtap

Μετά μπορείς να το χρησιμοποιήσεις κανονικά. Το ASCII mode λειτουργεί και με search:

playyt --search "linux tutorial" ascii

Εγκατάσταση

Το script υποστηρίζει όλες τις κύριες Linux διανομές. Αρκεί να το κάνεις executable:

chmod +x playyt

Θα χρειαστείς mpv (ή ffplay) και yt-dlp. Το καλό με το playyt είναι ότι κάνει αυτόματα check αν έχεις τα dependencies και αν κάτι λείπει, σου δίνει ακριβείς οδηγίες εγκατάστασης ανάλογα με τη διανομή σου. Υποστηρίζει Arch, Fedora/Nobara, Debian/Ubuntu, openSUSE, Gentoo, Alpine, Void, Solus, NixOS, RHEL/CentOS και άλλες.

Για Fedora/Nobara για παράδειγμα:

python3 -m pip install --user -U yt-dlp
sudo dnf install mpv ffmpeg

Αλλά το script θα σου πει ακριβώς τι να κάνεις αν λείπει κάτι, οπότε δεν χρειάζεται να θυμάσαι τις εντολές.

Χρήση σε άλλα scripts και GUI

Επειδή είναι απλό bash script, μπορείς να το ενσωματώσεις παντού. Αν έχεις ένα GUI script που θέλει να παίξει YouTube βίντεο, μπορείς να καλέσεις το playyt:

playyt "$youtube_url" &

Ή αν θες να δημιουργήσεις ένα custom launcher που παίρνει URLs από το clipboard:

#!/bin/bash
url=$(xclip -o)
playyt "$url"

Αυτό είναι ιδιαίτερα χρήσιμο αν δεν θέλεις να ανοίγεις browser tabs για YouTube. Μπορείς να έχεις ένα keyboard shortcut ή ένα GUI button που καλεί το playyt και παίζει το βίντεο απευθείας.

Είναι αρκετά ευέλικτο γιατί απλά παίρνει ένα URL και το τρέχει. Δεν έχει dependencies σε Emacs, browser extensions, ή τίποτα άλλο.

Γιατί playyt αντί για yeetube

Το yeetube είναι ωραίο αν ήδη χρησιμοποιείς Emacs. Αλλά αν δεν χρησιμοποιείς Emacs, δεν μπορείς να το χρησιμοποιήσεις. Το playyt δίνει την ίδια λειτουργικότητα σε όσους δεν θέλουν ή δεν χρησιμοποιούν Emacs:

  • Δεν χρειάζεται Emacs. Απλά bash script που τρέχει σε οποιοδήποτε terminal.
  • Λειτουργεί σε όλες τις διανομές. Το script έχει built-in detection για όλες τις κύριες Linux διανομές και σου λέει πως να εγκαταστήσεις dependencies.
  • Εύκολη ενσωμάτωση. Μπορείς να το χρησιμοποιήσεις σε οποιοδήποτε script, GUI application, ή keyboard shortcut.
  • Lightweight. Είναι ένα bash script, όχι full package ecosystem.

Η βασική ιδέα είναι να έχεις την ίδια λειτουργικότητα με το yeetube, αλλά για όλες τις διανομές και χωρίς Emacs dependency.

Τεχνικές λεπτομέρειες

Το script έχει ένα σημαντικό πλεονέκτημα: χρησιμοποιεί πολλαπλά fallback mechanisms για να βεβαιωθεί ότι θα λειτουργήσει. Πρώτα προσπαθεί να χρησιμοποιήσει το mpv απευθείας με το URL (που συχνά “απλά δουλεύει” αν το mpv έχει ytdl support). Αν αυτό αποτύχει, δοκιμάζει με explicit ytdl format. Αν και αυτό αποτύχει, παίρνει το direct media URL μέσω yt-dlp και το τρέχει στο mpv.

Αυτό σημαίνει ότι λειτουργεί ακόμα και αν το mpv δεν έχει compiled-in ytdl support, αρκεί να έχεις το yt-dlp στο PATH.

Το ίδιο ισχύει και για το ASCII mode. Το script ελέγχει αυτόματα ποια ASCII players είναι διαθέσιμα και χρησιμοποιεί αυτό που βρίσκει. Αν δεν βρει τίποτα, σου λέει ακριβώς τι να εγκαταστήσεις για τη διανομή σου.

Συμπέρασμα

Το playyt είναι η λύση για όσους θέλουν την ίδια λειτουργικότητα με το yeetube, αλλά χωρίς Emacs. Είναι ένα bash script που λειτουργεί σε όλες τις Linux διανομές, με αυτόματες οδηγίες εγκατάστασης dependencies, και με τη δυνατότητα ενσωμάτωσης σε άλλα scripts ή GUI applications.

Αν ήδη χρησιμοποιείς Emacs και σου αρέσει το yeetube, μείνε εκεί. Αλλά αν θέλεις να μην ανοίγεις browser tabs για YouTube και δεν χρησιμοποιείς Emacs, το playyt είναι η λύση. Απλά δίνεις ένα URL στο terminal και παίζει το βίντεο με mpv. Αν θες κάτι πιο retro, μπορείς να το δεις και ως ASCII art απευθείας στο terminal.

Το script είναι διαθέσιμο στο GitHub αλλά το έχω σε private repo, οπότε θα σας το postάρω εδώ…


#!/usr/bin/env bash
# playyt - play a youtube (or other yt-dlp supported) URL using yt-dlp + mpv/ffplay
# Alternative to yeetube (Emacs Lisp package) for terminal/CLI usage
# Usage: playyt <url> [player]
# Example: playyt "https://www.youtube.com/watch?v=..." mpv
#          playyt "https://www.youtube.com/watch?v=..." ffplay

# Use set -e but allow fallback logic with || operators
set -u

# Function to check if a command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to detect system and package manager
detect_system() {
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS=$NAME
    else
        OS=$(uname -s)
    fi

    case $OS in
        "Arch Linux"|"CachyOS"|"EndeavourOS"|"Manjaro Linux"|"Garuda Linux"|"ArcoLinux"|"Artix Linux")
            echo "arch"
            ;;
        "Fedora Linux"|"Fedora"|"Nobara Linux"|"Nobara")
            echo "fedora"
            ;;
        "Ubuntu"|"Debian GNU/Linux"|"Linux Mint"|"Pop!_OS"|"Zorin OS"|"elementary OS"|"Kali GNU/Linux"|"Parrot OS")
            echo "debian"
            ;;
        "openSUSE"*|"SUSE"*)
            echo "opensuse"
            ;;
        "Gentoo")
            echo "gentoo"
            ;;
        "Alpine Linux")
            echo "alpine"
            ;;
        "Void")
            echo "void"
            ;;
        "Solus")
            echo "solus"
            ;;
        "Clear Linux"*)
            echo "clearlinux"
            ;;
        "NixOS")
            echo "nixos"
            ;;
        "Red Hat"*|"CentOS"*|"Rocky Linux"|"AlmaLinux"|"Oracle Linux")
            echo "rhel"
            ;;
        *)
            echo "unknown"
            ;;
    esac
}

# Function to get installation command for a dependency
get_install_command() {
    local dep=$1
    local system=$2
    
    case $dep in
        yt-dlp)
            case $system in
                arch)
                    echo "sudo pacman -S --noconfirm yt-dlp"
                    ;;
                fedora|rhel)
                    echo "sudo dnf install -y yt-dlp"
                    ;;
                debian)
                    echo "sudo apt update && sudo apt install -y yt-dlp"
                    ;;
                opensuse)
                    echo "sudo zypper install -y yt-dlp"
                    ;;
                gentoo)
                    echo "sudo emerge -av net-misc/yt-dlp"
                    ;;
                alpine)
                    echo "sudo apk add yt-dlp"
                    ;;
                void)
                    echo "sudo xbps-install -y yt-dlp"
                    ;;
                solus)
                    echo "sudo eopkg install -y yt-dlp"
                    ;;
                clearlinux)
                    echo "sudo swupd bundle-add media-processing"
                    ;;
                nixos)
                    echo "nix-env -iA nixos.yt-dlp"
                    ;;
                *)
                    echo "pip install --user yt-dlp  # or: sudo pip install yt-dlp"
                    ;;
            esac
            ;;
        mpv)
            case $system in
                arch)
                    echo "sudo pacman -S --noconfirm mpv"
                    ;;
                fedora|rhel)
                    echo "sudo dnf install -y mpv"
                    ;;
                debian)
                    echo "sudo apt update && sudo apt install -y mpv"
                    ;;
                opensuse)
                    echo "sudo zypper install -y mpv"
                    ;;
                gentoo)
                    echo "sudo emerge -av media-video/mpv"
                    ;;
                alpine)
                    echo "sudo apk add mpv"
                    ;;
                void)
                    echo "sudo xbps-install -y mpv"
                    ;;
                solus)
                    echo "sudo eopkg install -y mpv"
                    ;;
                clearlinux)
                    echo "sudo swupd bundle-add media"
                    ;;
                nixos)
                    echo "nix-env -iA nixos.mpv"
                    ;;
                *)
                    echo "Please install mpv using your distribution's package manager"
                    ;;
            esac
            ;;
        ffmpeg|ffplay)
            case $system in
                arch)
                    echo "sudo pacman -S --noconfirm ffmpeg"
                    ;;
                fedora|rhel)
                    echo "sudo dnf install -y ffmpeg"
                    ;;
                debian)
                    echo "sudo apt update && sudo apt install -y ffmpeg"
                    ;;
                opensuse)
                    echo "sudo zypper install -y ffmpeg"
                    ;;
                gentoo)
                    echo "sudo emerge -av media-video/ffmpeg"
                    ;;
                alpine)
                    echo "sudo apk add ffmpeg"
                    ;;
                void)
                    echo "sudo xbps-install -y ffmpeg"
                    ;;
                solus)
                    echo "sudo eopkg install -y ffmpeg"
                    ;;
                clearlinux)
                    echo "sudo swupd bundle-add media-processing"
                    ;;
                nixos)
                    echo "nix-env -iA nixos.ffmpeg"
                    ;;
                *)
                    echo "Please install ffmpeg using your distribution's package manager"
                    ;;
            esac
            ;;
    esac
}

# Function to check dependency and provide helpful error message
check_dependency() {
    local dep=$1
    local system=$2
    
    if ! command_exists "$dep"; then
        echo "ERROR: $dep is not installed." >&2
        echo "" >&2
        echo "To install $dep, run:" >&2
        local install_cmd
        install_cmd=$(get_install_command "$dep" "$system")
        echo "  $install_cmd" >&2
        echo "" >&2
        
        # Special note for yt-dlp - pip is universal and often more up-to-date
        if [ "$dep" = "yt-dlp" ]; then
            if [ "$system" = "fedora" ] || [ "$system" = "rhel" ]; then
                echo "" >&2
                echo "For Fedora/Nobara, recommended installation via pip:" >&2
                echo "  python3 -m pip install --user -U yt-dlp" >&2
            elif [ "$system" = "unknown" ]; then
                echo "" >&2
                echo "Alternatively, install via pip (universal):" >&2
                echo "  python3 -m pip install --user -U yt-dlp" >&2
                echo "  # or download standalone binary from: https://github.com/yt-dlp/yt-dlp/releases" >&2
            fi
        fi
        
        return 1
    fi
    return 0
}

# Function to search YouTube and get first result URL
search_youtube() {
    local query="$1"
    local count="${2:-1}"
    
    # Use yt-dlp's ytsearch functionality
    # We want the webpage URL (like https://www.youtube.com/watch?v=...) so mpv can handle it
    local result
    local url
    local title
    
    # Get both title and URL in one call
    result=$(yt-dlp "ytsearch${count}:${query}" --print "%(title)s" --print "%(webpage_url)s" --no-warnings 2>/dev/null | head -n2)
    
    if [ -z "$result" ]; then
        echo "ERROR: No results found for: $query" >&2
        return 1
    fi
    
    # Parse result: first line is title, second is URL
    title=$(echo "$result" | head -n1)
    url=$(echo "$result" | tail -n1)
    
    if [ -n "$title" ]; then
        echo "Found: $title" >&2
    fi
    
    if [ -z "$url" ]; then
        echo "ERROR: Could not extract URL from search results" >&2
        return 1
    fi
    
    echo "$url"
}

# Main script
# Handle special flags
SEARCH_MODE=false
SEARCH_COUNT=1
URL=""
PLAYER=""
QUERY=""

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --search|-s)
            SEARCH_MODE=true
            if [ -z "${2:-}" ] || [[ "$2" == -* ]]; then
                echo "ERROR: --search requires a query string" >&2
                exit 2
            fi
            QUERY="$2"
            shift 2
            ;;
        --search-count|-n)
            if [ -z "${2:-}" ] || [[ "$2" == -* ]]; then
                echo "ERROR: --search-count requires a number" >&2
                exit 2
            fi
            SEARCH_COUNT="$2"
            shift 2
            ;;
        --help|-h)
            echo "Usage: $0 <url> [player: mpv|ffplay|ascii]" >&2
            echo "       $0 --search \"query\" [player]" >&2
            echo "" >&2
            echo "Options:" >&2
            echo "  --search, -s <query>    Search YouTube and play first result" >&2
            echo "  --search-count, -n <n>   When searching, get top N results (default: 1)" >&2
            echo "  --help, -h              Show this help message" >&2
            echo "" >&2
            echo "Players:" >&2
            echo "  mpv      - Default video player (best quality)" >&2
            echo "  ffplay   - Alternative player" >&2
            echo "  ascii   - Play video as ASCII art in terminal" >&2
            echo "" >&2
            echo "Examples:" >&2
            echo "  $0 'https://www.youtube.com/watch?v=...' mpv" >&2
            echo "  $0 'https://www.youtube.com/watch?v=...' ffplay" >&2
            echo "  $0 'https://www.youtube.com/watch?v=...' ascii" >&2
            echo "  $0 --search 'linux tutorial' ascii" >&2
            echo "" >&2
            echo "Notes:" >&2
            echo "  - For Fedora/Nobara, install yt-dlp via: python3 -m pip install --user -U yt-dlp" >&2
            echo "  - For ASCII mode, install mplayer with caca support or vtap (pip install vtap)" >&2
            echo "  - For a full TUI experience with search, consider: ytfzf (https://github.com/pystardust/ytfzf)" >&2
            exit 0
            ;;
        *)
            # If this looks like a flag, it's an error
            if [[ "$1" == -* ]]; then
                echo "ERROR: Unknown option: $1" >&2
                echo "Use --help for usage information." >&2
                exit 2
            fi
            
            # First non-flag argument is URL (if not in search mode) or player (if in search mode)
            if [ "$SEARCH_MODE" = true ]; then
                # In search mode, any remaining argument is the player
                if [ -z "$PLAYER" ]; then
                    PLAYER="$1"
                else
                    echo "WARNING: Ignoring extra argument: $1" >&2
                fi
            else
                # Normal mode: first is URL, second is player
                if [ -z "$URL" ]; then
                    URL="$1"
                elif [ -z "$PLAYER" ]; then
                    PLAYER="$1"
                else
                    echo "WARNING: Ignoring extra argument: $1" >&2
                fi
            fi
            shift
            ;;
    esac
done

# Set default player if not specified
PLAYER="${PLAYER:-mpv}"

# Handle search mode
if [ "$SEARCH_MODE" = true ]; then
    if [ -z "$QUERY" ]; then
        echo "ERROR: --search requires a query string" >&2
        echo "Usage: $0 --search 'your query here' [player]" >&2
        exit 2
    fi
    
    echo "Searching YouTube for: $QUERY" >&2
    URL=$(search_youtube "$QUERY" "$SEARCH_COUNT")
    
    if [ -z "$URL" ]; then
        exit 1
    fi
fi

if [ -z "$URL" ]; then
    echo "Usage: $0 <url> [player: mpv|ffplay|ascii]" >&2
    echo "       $0 --search \"query\" [player]" >&2
    echo "" >&2
    echo "Use --help for more options." >&2
    exit 2
fi

# Detect system for dependency checks
SYSTEM=$(detect_system)

# Check required dependencies
MISSING_DEPS=()

# Always check for yt-dlp (required)
if ! check_dependency "yt-dlp" "$SYSTEM"; then
    MISSING_DEPS+=("yt-dlp")
fi

# Function to check for ASCII player tools
check_ascii_player() {
    local system=$1
    
    # Check for vtap first (Python-based, best YouTube support, easy to install)
    if command_exists vtap; then
        echo "vtap"
        return 0
    fi
    
    # Check for tplay (Rust-based, good YouTube support)
    if command_exists tplay; then
        echo "tplay"
        return 0
    fi
    
    # Check for mplayer with caca support
    if command_exists mplayer; then
        if mplayer -vo help 2>/dev/null | grep -q caca; then
            echo "mplayer"
            return 0
        fi
    fi
    
    # Check for mpv with caca support
    if command_exists mpv; then
        if mpv --vo=help 2>/dev/null | grep -q caca; then
            echo "mpv"
            return 0
        fi
    fi
    
    return 1
}

# Check for player-specific dependencies
case "$PLAYER" in
    mpv)
        if ! check_dependency "mpv" "$SYSTEM"; then
            MISSING_DEPS+=("mpv")
        fi
        ;;
    ffplay)
        if ! check_dependency "ffmpeg" "$SYSTEM"; then
            MISSING_DEPS+=("ffmpeg")
        fi
        # Also check if ffplay exists (part of ffmpeg package)
        if ! command_exists "ffplay"; then
            echo "ERROR: ffplay not found (should be part of ffmpeg package)." >&2
            MISSING_DEPS+=("ffmpeg")
        fi
        ;;
        ascii)
        ASCII_PLAYER=$(check_ascii_player "$SYSTEM")
        if [ -z "$ASCII_PLAYER" ]; then
            echo "ERROR: No ASCII video player found." >&2
            echo "" >&2
            echo "To use ASCII mode, install one of the following (vtap is recommended for best YouTube support):" >&2
            echo "" >&2
            echo "  1. vtap (Python-based, RECOMMENDED - best YouTube support):" >&2
            echo "     pip install --user vtap" >&2
            echo "     # or: python3 -m pip install --user vtap" >&2
            echo "" >&2
            echo "  2. tplay (Rust-based, good YouTube support):" >&2
            echo "     See: https://github.com/maxcurzi/tplay" >&2
            echo "" >&2
            echo "  3. mplayer with caca support:" >&2
            case $SYSTEM in
                arch)
                    echo "     sudo pacman -S --noconfirm mplayer" >&2
                    ;;
                fedora|rhel)
                    echo "     sudo dnf install -y mplayer" >&2
                    ;;
                debian)
                    echo "     sudo apt update && sudo apt install -y mplayer" >&2
                    ;;
                *)
                    echo "     Install mplayer package from your distribution" >&2
                    ;;
            esac
            echo "" >&2
            echo "Note: vtap is the easiest to install and has the best YouTube compatibility." >&2
            MISSING_DEPS+=("ascii-player")
        else
            # If using mplayer or mpv (legacy tools), suggest vtap for better experience
            if [ "$ASCII_PLAYER" = "mplayer" ] || [ "$ASCII_PLAYER" = "mpv" ]; then
                echo "Note: Using $ASCII_PLAYER for ASCII playback." >&2
                echo "      For better YouTube support, consider installing vtap: pip install --user vtap" >&2
            fi
        fi
        ;;
    *)
        # Custom player - just check if it exists
        if ! command_exists "$PLAYER"; then
            echo "ERROR: Player '$PLAYER' not found." >&2
            exit 1
        fi
        # Still need yt-dlp for custom players
        ;;
esac

# Exit if dependencies are missing
if [ ${#MISSING_DEPS[@]} -ne 0 ]; then
    echo "" >&2
    echo "Please install the missing dependencies and try again." >&2
    exit 1
fi

# Play the video
case "$PLAYER" in
    mpv)
        # mpv has built-in ytdl:// protocol support and can use yt-dlp automatically
        # Strategy: Try simplest approach first, then fallback to more explicit methods
        if command_exists mpv; then
            # First: Try mpv directly (often "just works" if mpv has ytdl support and yt-dlp is in PATH)
            # Suppress stderr for first attempt (may show warnings we can ignore if it works)
            if mpv "$URL" 2>/dev/null; then
                exit 0
            fi
            
            # Second: Try with explicit ytdl format (mpv will use yt-dlp if available)
            if mpv --ytdl-format=best "$URL" 2>/dev/null; then
                exit 0
            fi
            
            # Third: Fallback - get direct media URL using yt-dlp and feed to mpv (most portable)
            # This method works even if mpv doesn't have ytdl support compiled in
            STREAM_URL="$(yt-dlp -f best -g "$URL" 2>/dev/null | head -n1)"
            if [ -n "$STREAM_URL" ]; then
                mpv "$STREAM_URL"
                exit $?
            else
                echo "ERROR: Could not resolve stream URL with yt-dlp." >&2
                echo "Make sure yt-dlp is installed and the URL is valid." >&2
                echo "Try running: yt-dlp '$URL' to debug." >&2
                exit 1
            fi
        fi
        ;;
    ffplay)
        # stream via stdout into ffplay using ffmpeg (ffplay)
        if command_exists ffplay; then
            # use yt-dlp to output raw media to stdout, pipe to ffplay
            yt-dlp -f best -o - "$URL" 2>/dev/null | ffplay -autoexit -nodisp -i -
            exit $?
        fi
        ;;
    ascii)
        # ASCII video playback in terminal
        ASCII_PLAYER=$(check_ascii_player "$SYSTEM")
        
        if [ -z "$ASCII_PLAYER" ]; then
            echo "ERROR: No ASCII player found." >&2
            exit 1
        fi
        
        case "$ASCII_PLAYER" in
            mplayer)
                # mplayer with caca output
                # mplayer doesn't handle HLS well, so try to get non-HLS format first
                echo "Getting stream URL with yt-dlp..." >&2
                STREAM_URL="$(yt-dlp -f 'best[ext=mp4][protocol!=m3u8]/best[ext=webm][protocol!=m3u8]/best[protocol!=m3u8]' -g "$URL" 2>/dev/null | head -n1)"
                
                if [ -z "$STREAM_URL" ]; then
                    # Fallback: try best non-HLS format
                    STREAM_URL="$(yt-dlp -f 'best[protocol!=m3u8]' -g "$URL" 2>/dev/null | head -n1)"
                fi
                
                # Check if we got HLS anyway
                if echo "$STREAM_URL" | grep -q '\.m3u8\|manifest\|/hls_'; then
                    echo "WARNING: Got HLS stream which mplayer doesn't handle well." >&2
                    echo "Try using mpv instead or install vtap for better YouTube support." >&2
                    # Still try it but with warning
                fi
                
                if [ -n "$STREAM_URL" ]; then
                    # Use -really-quiet, -nolirc, -nomouseinput to avoid conflicts
                    # -framedrop helps with performance
                    # -cache 8192 for better buffering
                    timeout 30 mplayer -really-quiet -vo caca -nolirc -nomouseinput -noconfig all -framedrop -cache 8192 "$STREAM_URL" 2>/dev/null
                    EXIT_CODE=$?
                    if [ $EXIT_CODE -eq 124 ]; then
                        echo "mplayer timed out or had issues. The stream format may not be compatible." >&2
                    fi
                    exit $EXIT_CODE
                else
                    echo "ERROR: Could not extract compatible stream URL for mplayer." >&2
                    echo "YouTube may only provide HLS streams for this video." >&2
                    exit 1
                fi
                ;;
            mpv)
                # mpv with caca output
                # mpv handles HLS better, but still try non-HLS first for better compatibility
                STREAM_URL="$(yt-dlp -f 'best[protocol!=m3u8]/best' -g "$URL" 2>/dev/null | head -n1)"
                if [ -n "$STREAM_URL" ]; then
                    mpv --quiet --vo=caca "$STREAM_URL" 2>/dev/null
                    exit $?
                else
                    mpv --quiet --vo=caca "$URL" 2>/dev/null
                    exit $?
                fi
                ;;
            vtap)
                # vtap supports YouTube URLs but needs -u flag
                # vtap uses pytube which sometimes has API issues, so try it first but fallback if it fails
                echo "Attempting to play with vtap..." >&2
                # Try vtap, suppress verbose traceback output (we know it has pytube issues)
                if ! vtap -u "$URL" 2>/dev/null; then
                    VTAP_ERROR=$?
                    # vtap failed, try fallback
                    echo "" >&2
                    echo "WARNING: vtap failed (pytube library may have YouTube API issues)." >&2
                    echo "Falling back to alternative ASCII player..." >&2
                    echo "" >&2
                    
                    # Download video to temp file first (most reliable for ASCII playback)
                    echo "Downloading video temporarily for ASCII playback..." >&2
                    TEMP_DIR=$(mktemp -d)
                    TEMP_FILE="$TEMP_DIR/video.%(ext)s"
                    trap "rm -rf '$TEMP_DIR'" EXIT
                    
                    # Download video (limit to 720p for faster download, ASCII doesn't need high quality)
                    yt-dlp -f 'best[height<=720]' -o "$TEMP_FILE" "$URL" --no-warnings 2>&1
                    
                    # Find downloaded file (yt-dlp adds extension automatically)
                    DOWNLOADED_FILE=$(find "$TEMP_DIR" -type f -size +100k 2>/dev/null | head -n1)
                    
                    if [ -n "$DOWNLOADED_FILE" ] && [ -s "$DOWNLOADED_FILE" ]; then
                        echo "Download successful. Playing with ASCII player..." >&2
                        # Prefer mpv, fallback to mplayer
                        if command_exists mpv && mpv --vo=help 2>/dev/null | grep -q caca; then
                            mpv --quiet --vo=caca --framedrop=decoder "$DOWNLOADED_FILE" 2>/dev/null
                            EXIT_CODE=$?
                            rm -rf "$TEMP_DIR"
                            exit $EXIT_CODE
                        elif command_exists mplayer && mplayer -vo help 2>/dev/null | grep -q caca; then
                            mplayer -really-quiet -vo caca -nolirc -nomouseinput -noconfig all -framedrop "$DOWNLOADED_FILE" 2>/dev/null
                            EXIT_CODE=$?
                            rm -rf "$TEMP_DIR"
                            exit $EXIT_CODE
                        else
                            rm -rf "$TEMP_DIR"
                            echo "ERROR: No ASCII player found." >&2
                            exit 1
                        fi
                    else
                        echo "Download failed or incomplete. File not found or too small." >&2
                        rm -rf "$TEMP_DIR"
                    fi
                    
                    # Final fallback: try mpv with stream (it handles HLS better)
                    if command_exists mpv && mpv --vo=help 2>/dev/null | grep -q caca; then
                        echo "Attempting direct stream with mpv as last resort..." >&2
                        STREAM_URL="$(yt-dlp -f 'best[height<=480]' -g "$URL" 2>/dev/null | head -n1)"
                        if [ -n "$STREAM_URL" ]; then
                            mpv --quiet --vo=caca --framedrop=decoder "$STREAM_URL" 2>/dev/null
                            exit $?
                        fi
                    fi
                    
                    echo "ERROR: All ASCII players failed." >&2
                    echo "vtap has YouTube API issues (pytube library). Try updating: pip install --upgrade --user vtap" >&2
                    exit $VTAP_ERROR
                fi
                exit 0
                ;;
            tplay)
                # tplay supports YouTube URLs directly
                tplay "$URL"
                exit $?
                ;;
            *)
                echo "ERROR: Unknown ASCII player: $ASCII_PLAYER" >&2
                exit 1
                ;;
        esac
        ;;
    *)
        # custom player passed by user
        if command_exists "$PLAYER"; then
            STREAM_URL="$(yt-dlp -f best -g "$URL" 2>/dev/null | head -n1)"
            if [ -n "$STREAM_URL" ]; then
                "$PLAYER" "$STREAM_URL"
                exit $?
            else
                echo "ERROR: Could not resolve stream URL." >&2
                exit 1
            fi
        fi
        ;;
esac

echo "ERROR: No suitable player found (mpv/ffplay)." >&2
exit 1

έγινε edit πάλι 2025-11-01 @ 16:45 γιατί ήθελα καλύτερο fallback αν δε μπορεί με ascii σωστά να το δείξει, το κάνει λήψη και αναπαραγωγή, παραθέτω και το αποτέλεσμα..

image