From baa80d2473765667e11cd98eacde3301de8d8f96 Mon Sep 17 00:00:00 2001 From: Maxim Likhachev Date: Sat, 10 Oct 2020 18:23:28 +0300 Subject: [PATCH] mptk: use direct connection to mpd without mpc --- scripts/mptk | 210 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 156 insertions(+), 54 deletions(-) diff --git a/scripts/mptk b/scripts/mptk index 165f311..608cb4b 100755 --- a/scripts/mptk +++ b/scripts/mptk @@ -1,85 +1,187 @@ #!/usr/bin/env tclsh -# Ghetto MPD controller +# Copyright (C) 2020, Maxim Lihachev, +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# +# Offhand MPD controller +# +# Requirements: +# +# - mid3v2 +# package require Tk set music_directory "/mnt/DATA/Музыка/" -array set buttons { - prev 玲 - toggle ▶ - next 怜 -} +namespace eval mpd { + array set settings { + host 127.0.0.1 + port 6600 + } -set used_ratings {1 2 3 4 5 5+} + proc cmd {args} { + set mpd [socket $::mpd::settings(host) $::mpd::settings(port)] + + puts $mpd $args + puts $mpd close + flush $mpd + + set mpd_answer [split [read $mpd] "\n"] + set mpd_status [lindex $mpd_answer 0] + set answer_code [lindex $mpd_answer end-1] + + if {$answer_code == "OK"} { + if {![string match "ACK*" $answer_code]} { + return [lrange $mpd_answer 1 end-2] + } else { + return $answer_code + } + } else { + return "ERROR: $mpd_answer" + } + } -proc mpc {args} { - exec mpc {*}$args -} + proc status {} { + set currentsong [::mpd::cmd currentsong] + set status [::mpd::cmd status] + + if {![string match "ERROR:*" $currentsong] && ![string match "ERROR:*" $status]} { + array set song {} + foreach metadata [list {*}$currentsong {*}$status] { + regexp -expanded {^([^:]+):\s+(.*)$} $metadata match key value + set song([string tolower $key]) $value + } + + if {$song(state) != "stop"} { + if {[info exists song(comment)]} { + ::gui::hl_rating $song(comment) + } + + return [format "♫ %s/%s: %s - %s\n\[%s - %s\]\n~ %s ~\n\[%s\] repeat: %s random: %s single: %s consume: %s" \ + [incr song(song)] $song(playlistlength) \ + $song(artist) $song(title) $song(date) \ + $song(album) $song(genre) $song(state) \ + [state $song(repeat)] [state $song(random)] \ + [state $song(single)] [state $song(consume)]] + } else { + return "\[stopped\]" + } + } else { + return "${currentsong}\n${status}" + } + } -proc current_file {} { - set filename [file join $::music_directory [lindex [split [exec mpc -f {%file%}] "\n"] 0]] -} + proc state {code} { + expr {$code == 0 ? {✘} : {✔}} + } -proc rate {rating} { - set filename [current_file] + proc value {data} { + regsub {^[^:]*:\s+} $data {} + } + + proc current_file {} { + set filename [file join $::music_directory [value [lindex [cmd currentsong] 0]]] + } - exec mid3v2 --delete-frames=COMM $filename - exec mid3v2 --COMM $rating $filename + proc previous {} { cmd previous } + proc next {} { cmd next } - hl_rating $rating + proc toggle {} { + set state [value [lindex [cmd status] 8]] - mpc update -} + if {$state == "stop" || $state == ""} { + cmd play + } else { + cmd pause + } + } + + proc consume {} { + set consume [value [lindex [cmd status] 4]] + cmd consume [expr {$consume == 1 ? 0 : 1}] + } -proc current_rating {} { - set filename [file join $::music_directory [current_file]] + proc random {} { + set random [value [lindex [cmd status] 2]] + cmd random [expr {$random == 1 ? 0 : 1}] + } + + proc rate {rating} { + set filename [current_file] + + exec mid3v2 --delete-frames=COMM $filename + exec mid3v2 --COMM $rating $filename - if {[catch {set rating [exec -ignorestderr exiftool -Comment $filename 2>/dev/null]}]} { - return {} - } else { - return [lindex [split $rating " "] end] + cmd update } } -proc hl_rating {rating} { - foreach r $::used_ratings { - if {[winfo exists .rating.$r]} { - set c [expr {$r == $rating ? {red2} : {black}}] - .rating.$r configure -activeforeground $c -foreground $c +namespace eval gui { + set used_ratings {1 2 3 4 5 5+} + + array set buttons { + previous 玲 + toggle ▶ + next 怜 + } + + proc hl_rating {rating} { + foreach r $::gui::used_ratings { + if {[winfo exists .rating.$r]} { + set c [expr {$r == $rating ? {red2} : {black}}] + .rating.$r configure -activeforeground $c -foreground $c + } } } -} -proc update_status {} { - set ::mpd_status [mpc] + proc update_status {} { + set ::mpd_status [::mpd::status] - hl_rating [current_rating] + after 1000 ::gui::update_status + } - after 1000 update_status -} + proc init {} { + frame .status + frame .rating -pady 10 + frame .control -pady 10 -frame .status -frame .rating -pady 10 -frame .control -pady 10 + pack .status -fill x -expand true -padx 20 -pady 20 + pack [label .status.current -font {Sans 20} -textvariable ::mpd_status] -pack .status -fill x -expand true -padx 20 -pady 20 -pack [label .status.current -font {Sans 20} -textvariable ::mpd_status] + pack .rating + foreach rating $::gui::used_ratings { + pack [button .rating.$rating -text $rating -font {Sans 60} -width 2 -command "::mpd::rate $rating"] -side left + } -pack .rating -foreach rating $::used_ratings { - pack [button .rating.$rating -text $rating -font {Sans 60} -width 2 -command "rate $rating"] -side left -} + pack .control + foreach btn {previous toggle next} { + pack [button .control.$btn -text $::gui::buttons($btn) -font {Sans 80} -width 4 -command "::mpd::$btn"] -side left + } -pack .control -foreach btn {prev toggle next} { - pack [button .control.$btn -text $buttons($btn) -font {Sans 80} -width 4 -command "mpc $btn"] -side left -} + #---------------------------------------------------------------------------------------- -update_status + update_status + + bind . {::mpd::random} + bind . {::mpd::consume} + + bind . exit + bind . exit + } +} -bind . {mpc random} -bind . exit -bind . exit +gui::init