Playing YouTube Videos

Created by CecilWesterhof.

I created a little script to play YouTube videos with mpv. There were several reasons for this:

  • When playing in my browser it takes a lot more resources as when playing with mpv.
  • I want to play the videos in a higher speed. But the speed is depending on the type of video.
  • I prefer the interface of mpv.

I was planning to make a graphical version also. Will probably still do this, but it does not have a high priority anymore, because most things I want are now implemented in the command line version. It would be nice to use for example just 2 instead of:

2 |Enter| |Shift|+|Insert| |Enter|

But there are a 'few' things I find more important.

Current functionality:

  • Fetch values for speed for the keys 1-0 out of SQLite database.
  • Display the speeds.
  • Enter loop
  • Ask for URL while also displaying current speed.
  • If it is #q quit.
  • If it is 1-0 set new speed.
  • If it is speeds display speeds.
  • If it is a valid YouTube URL call mpv with it and the correct speed.
  • Otherwise give an error message.

When I will make the Tk version, this will add at least the following functionalities:

  • The value of the URL will be fetched from the clipboard.
  • Starting is done by the keys 1 to 0.

Any ideas for extra functionalities are welcome.

The code:

#!/usr/bin/env tclsh


package require sqlite3


proc displaySpeeds {} {
    global speeds

    dict for {key speed} $speeds {
        puts [format "%s: %4.2f" $key $speed]
    }
}

proc getInput {prompt} {
    if {($prompt ne "") && ([string index $prompt end] ne " ")} {
        set prompt "$prompt: "
    }
    puts  -nonewline $prompt
    flush stdout
    gets  stdin
}

proc init {} {
    global currentKey
    global currentSpeed
    global speeds

    set     getSpeed "
    SELECT speed
    FROM   playYouTubeVideo
    WHERE  key = :key
"
    set     keys [list 1 2 3 4 5 6 7 8 9 0]

    set     speeds [dict create]
    sqlite  db ~/.tcl.sqlite
    db      timeout [expr {10 * 1000}]
    foreach key $keys {
        set  speed [db eval $getSpeed]
        if {$speed == ""} {
            error "Cannot retrieve speed for $key"
        }
        dict append speeds $key $speed
    }
    db      close
    set     currentKey 1
    set     currentSpeed [dict get $speeds $currentKey]
    displaySpeeds
}

proc setSpeed {key} {
    global currentKey
    global currentSpeed
    global speeds

    if {[dict exists $speeds $key]} {
        set currentKey   $key
        set currentSpeed [dict get $speeds $currentKey]
    } else {
        puts "$key is a wrong key."
    }
}


init
while {True} {
    set prompt [format "Enter YouTube URL (#q to exit) (%s, %4.2f): " \
                    $currentKey $currentSpeed]
    set URL    [getInput $prompt]
    # Remove parameters if necessary
    if {[string index $URL 43] eq "&"} {
        set URL [string range $URL 0 42]
    }
    if {$URL eq "#q"} {
        break
    } elseif {[string length $URL] == 1} {
        setSpeed $URL
    } elseif {$URL eq "speeds"} {
        displaySpeeds
    } elseif {[regexp {^https://www.youtube.com/watch\?v=(.){11}$} $URL]} {
        exec mpv --speed $currentSpeed $URL >&/dev/null
    } else {
        puts "Not a valid YouTube URL: $URL"
    }
}

Definition of the table:

CREATE TABLE playYouTubeVideo (
    key     TEXT    NOT NULL,
    speed   FLOAT   NOT NULL,

    CONSTRAINT key   CHECK(length(key)  == 1),
    CONSTRAINT speed CHECK(TYPEOF(speed) = "real"),

    PRIMARY KEY(key)
);

At the moment I use the keys 1-0. All ten keys have to appear in the database. The values for speed also have to be reals: so use 1.0 instead of 1.


As always: comments, tips and questions are appreciated.

DDG Very interesting. As mpv supports like mplayer the --wid option for embedding, you might be use my SnitMPlayer as a starting point for a graphical version. Please note, that mplayers slave mode was however replaced with JSON IPC See https://github.com/mpv-player/mpv/blob/master/DOCS/man/ipc.rst

CecilWesterhof That was not exactly what I was thinking, it is more that I thought a graphical interface has some benefits. But it is less important now: the changes I did to the command line version implement most of what I wanted for the graphical version. It would still be better, but not as much as with the original version.

DDG Anyway, inspired I just added youtube support to my SnitMPlayer. It uses youtube-dl commandline application in the background to retrieve the real video url.