Version 3 of Tcl MP3 Alarm Clock

Updated 2008-11-27 13:25:03 by peterc

Rationale

I (peterc) hate my city's shock jock monoculture, and the non-talkback stations here are more likely to put me back to sleep than wake me up.

Cron + a sound card + Tcl MP3 selector script + mpg123 + a 5 metre headphone extension cable + external PC speakers = No more terrible early morning radio!

mp3select.sh script

 #!/usr/local/ActiveTcl-8.5/bin/tclsh8.5
 package require fileutil

 ########
 # Essentials

 proc shuffle {list} {
  set n 1
  set slist {}
  foreach item $list {
   set index [expr {int(rand()*$n)}]
   set slist [linsert $slist $index $item]
   incr n
   }
  return $slist
  }

 proc lvarpop {upVar {index 0}} {
  upvar $upVar list;
  if {![info exists list]} { return "-1" }
  set top [lindex $list $index];
  set list [concat [lrange $list 0 [expr $index - 1]] [lrange $list [expr $index +1] end]]
  return $top;
  }

 ########
 # General

 proc get_dirs {} {
  if {![file exists $::dirs_file]} { puts "Error: $::dirs_file does not exist!" ; exit }
  if {![file readable $::dirs_file]} { puts "Error: $::dirs_file unreadable!" ; exit }
  set DF [open $::dirs_file "r"]
  fconfigure $DF -encoding binary -translation binary -buffering none
  set dirs [read $DF]
  close $DF
  return $dirs
  }

 ########
 # Core

 proc random_from_all {items} {
  # Create list
  set fl [list]
  set dirs [get_dirs]
  foreach d $dirs {
   set mp3 [fileutil::findByPattern $d *.mp3]
   foreach f $mp3 { lappend fl $f }
   }
  # puts "Full list:\n$fl\n";
  set fl [shuffle $fl]
  set c 0 ; while {$c < $items} { lappend pl [lvarpop fl 0] ; incr c }
  return $pl
  }

 proc ordered_from_random_dirs {items} {
  # Create list
  set fl [list]
  set dl [list]
  set dq [list]
  set pl [list]
  set dirs [get_dirs]
  foreach d $dirs {
   set found [fileutil::findByPattern $d *]
   foreach f $found {
    if {[file isdirectory $f] && [regexp $d $f] } { lappend dl $f }
    }
   }
  # Shuffle directories
  set dl [shuffle $dl]
  set c 0 ; while {$c < $items} { lappend dq [lvarpop dl 0] ; incr c }
  # Collect files inside directories
  foreach d $dq {
   set mp3 [lsort [fileutil::findByPattern $d -glob *.mp3]]
   foreach f $mp3 { lappend pl $f }
   }
  return $pl
  }

 proc set_directories_file {value} { set ::dirs_file $value }

 ########
 # Main

 interp alias {} -rdof {} ordered_from_random_dirs ;# Random Dirs, Ordered Files
 interp alias {} -rdrf {} random_from_all           ;# Random Dirs, Random Files
 interp alias {} -cf {} set_directories_file       ;# Sets your root dirs file.
 set ::dirs_file "~/.mp3select/dirs.conf"          ;# Sets a default root dirs file.

 foreach {opt value} $argv {
  foreach f [$opt $value] { puts $f ; set didsomething 1 }
  }

 if {![info exists didsomething]} {
  puts "Syntax:\n"
  puts " mp3select.sh opt value opt value \[...\]\n"
  puts "Options:\n"
  puts " -rdof X : Random Dirs, Ordered Files; to play X random audioplays."
  puts " -rdrf X : Random Files; for playing X random tracks."
  puts " -cf /path/file : Sets the path to the file with root directories.\n"
  puts "Example:\n"
  puts " mp3select.sh -rdrf 10 -cf ~/punk.cf -rdof 3\n"
  puts " This selects 10 random songs from the dirs in the default file,"
  puts " changes the dirs file to ~/punk.cf then selects 3 random albums.\n"
  puts "Notes:\n"
  puts " mp3select.sh will not select a song twice in the same option track"
  puts " selection. The -cf setting applies to the next -rdof/-rdrf"
  puts " file selection/s but not previous ones. Multiple -cf may be used."
  }

dirs.conf (and other conf/cf files)

Each file contains a list of root directories for your MP3 files, one per line. eg:

 /home/someuser/Music
 /data/Music

These root directories are searched recursively for playable MP3 files. You can list an unlimited number of root directories in each file, and of course, specify any number of conf/cf files on the command-line.

License

Originally by peterc. Standard BSD style license.

Use examples

Set up in Cron (using crontab -e):

 0 7 *  *  * * /pathto/mp3select.sh -rdrf 30 >/tmp/pl.txt && mpg123 -q -@ /tmp/pl.txt >/dev/null 2>&1

While I'm using the mpg123 app here, you can use MPlayer (using -playlist somefile.cf -really-quiet); or anything capable of reading a playlist/queue from a file.


enter categories here