Updated 2018-01-25 19:44:11 by CecilWesterhof

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}]

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."

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] == "&"} {
        set URL [string range ${URL} 0 42]
    if {${URL} == "#q"} {
    } elseif {[string length ${URL}] == 1} {
        setSpeed ${URL}
    } elseif {${URL} == "speeds"} {
    } 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.