#!/usr/bin/env ruby # Copyright (C) 2013-2015 all contributors # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) # # WARNING: totally unstable API, use dtas-ctl for scripting (but the protocol # itself is also unstable, but better than this one probably). require 'dtas/unix_client' require 'shellwords' def get_track_ids(c) track_ids = c.req("tl tracks") # we could get more, but SEQPACKET limits size... track_ids = track_ids.split(/ /) track_ids.shift track_ids end def do_edit(c) require 'dtas/edit_client' require 'yaml' require 'tempfile' extend DTAS::EditClient tmp = Tempfile.new(%w(dtas-tl-edit .txt)) tmp.binmode tmp_path = tmp.path orig = [] orig_idx = {} get_track_ids(c).each_slice(128) do |track_ids| res = c.req("tl get #{track_ids.join(' ')}") res = Shellwords.split(res.sub!(/\A\d+ /, '')) while line = res.shift line.sub!(/\A(\d+)=/, '') or abort "unexpected line=#{line.inspect}\n" track_id = $1.to_i orig_idx[track_id] = orig.size orig << track_id tmp.write("#{Shellwords.escape(line)} =#{track_id}\n") end end tmp.flush ed = editor # jump to the line of the currently playing track if using vi or vim # Patches for other editors welcome: dtas-all@nongnu.org if ed =~ /vim?\z/ cur = YAML.load(c.req('current')) if tl = cur['tracklist'] if pos = tl['pos'] ed += " +#{pos + 1}" end end end # Run the editor and let the user edit! system("#{ed} #{Shellwords.escape tmp_path}") or return edit = [] edit_idx = {} add = [] # editor may rename/link a new file into place File.open(tmp_path) do |fp| while line = fp.gets line.chomp! if line.sub!(/ =(\d+)\z/, '') # existing tracks track_id = $1.to_i if edit_idx[track_id] # somebody copy+pasted an existing line add << [ File.expand_path(line), edit.last ] else # moved line edit_idx[track_id] = edit.size edit << track_id end else # entirely new line add << [ File.expand_path(line), edit.last ] end end end edit.each_with_index do |track_id, i| oi = orig_idx[track_id] or warn("unknown track_id=#{track_id}") or next next if oi == i # no change, yay! prev_track_id = orig[i] or warn("unknown index at #{i}") or next c.req("tl swap #{track_id} #{prev_track_id}") orig_idx[track_id] = i orig_idx[prev_track_id] = oi orig[i] = track_id orig[oi] = prev_track_id end orig.each do |track_id| edit_idx[track_id] or c.req("tl remove #{track_id}") end add.each do |path, after_id| cmd = %W(tl add #{path}) cmd << after_id.to_s if after_id c.req(cmd) end ensure tmp.close! if tmp end c = DTAS::UNIXClient.new case cmd = ARGV[0] when "cat" get_track_ids(c).each do |track_id| res = c.req("tl get #{track_id}") res.sub!(/\A1 /, '') print "#{res}\n" end when "addhead" ARGV.shift ARGV.reverse.each do |path| path = File.expand_path(path) res = c.req(%W(tl add #{path})) print "#{path} #{res}\n" end when "addtail" ARGV.shift track_ids = get_track_ids(c) last_id = track_ids.pop ARGV.each do |path| path = File.expand_path(path) req = %W(tl add #{path}) req << last_id.to_s if last_id res = c.req(req) print "#{path} #{res}\n" last_id = res if res =~ /\A\d+\z/ end when "reto" fixed = ARGV.delete("-F") ignorecase = ARGV.delete("-i") re = ARGV[1] time = ARGV[2] re = Regexp.quote(re) if fixed re = ignorecase ? %r{#{re}}i : %r{#{re}} get_track_ids(c).each do |track_id| res = c.req("tl get #{track_id}") res.sub!(/\A1 \d+=/, '') if re =~ res req = %W(tl goto #{track_id}) req << time if time res = c.req(req) puts res exit(res == "OK") end end warn "#{re.inspect} not found" exit 1 when 'edit' then do_edit(c) else # act like dtas-ctl for now... puts c.req([ "tl", *ARGV ]) end