Finished the first draft (I think). Added options to documentation.

This commit is contained in:
Elf M. Sternberg 2014-12-06 16:05:37 -08:00
parent 36d8db1f86
commit a1dd0a8313
3 changed files with 85 additions and 21 deletions

18
README
View File

@ -1,4 +1,20 @@
This is a distribution of mp_suggest, an organization tool for MP3 libraries
This is a distribution of mp_suggest, an organization tool for MP3
libraries. It was written primarily as an experiment in learning Hy.
Hy is a lisp-like programming language that runs on top of the Python VM
and exploits Python's access to the running AST in order to build
working Python programs.
Writing mp_suggest was an interesting exercise in returning to Lisp
after all these years. I find that I really enjoyed it (although,
honestly, Hy's debugging facilities leave a lot to be desired). The
style used inside mp_suggest is most definitely not Lispy; looking
through it, with its persistent use of cheap anonymous functions and
closures and its function-level metaprogramming, I guess the best
language I could compare it to is Coffeescript. I like Coffeescript a
lot, but I don't get many opportunities to use it professionally, but
the sensibilities of Coffeescript (especially Reginald Braithwaite's
Ristrettology and his other books on functional programming) heavily
influenced the design decisions I made in mp_suggest.
* Licensing

View File

@ -17,35 +17,39 @@
(defn print-version []
(print (.format "mp_suggest (hy version {})" *version*))
(sys.exit 0))
(print "Copyright (c) 2008, 2014 Elf M. Sternberg <elf.sternberg@gmail.com>")
(sys.exit))
(defn print-help []
(print "Usage:")
(ap-each optlist (print (.format " -{} --{} {}" (get it 0) (get it 1) (get it 3))))
(sys.exit 0))
(sys.exit))
; Given a set of command-line arguments, compare that to a mapped
; version of the optlist and return a canonicalized dictionary of all
; the arguments that have been set.
(defn find-opt-reducer [acc it]
(let [[(, o a) it]
[optmap (ap-reduce (do (assoc acc (+ "-" (. it [0])) (. it [1])) acc) optlist {})]]
(if (.has_key optmap o) (let [[full (car (get optmap o))]
[hasargs (car (cdr (get optmap o)))]]
(assoc acc full (if hasargs a true))))
acc))
(defn make-opt-assoc [prefix pos]
(fn [acc it] (assoc acc (+ prefix (get it pos)) (get it 1)) acc))
(defn make-options-rationalizer [optlist]
(let [
[short-opt-assoc (make-opt-assoc "-" 0)]
[long-opt-assoc (make-opt-assoc "--" 1)]
[fullset
(ap-reduce (-> (short-opt-assoc acc it)
(long-opt-assoc it)) optlist {})]]
(fn [acc it] (do (assoc acc (get fullset (get it 0)) (get it 1)) acc))))
; Assuming the directory name looked like "Artist - Album", return the
; two names separately. If only one name is here, assume a compilation
; or mixtape album and default to "VA" (Various Artists).
(defn artist-album []
(let [[aa (.split (. (.split (.getcwd os) "/") [-1]) " - ")]
[sp (fn [i] (.strip i))]]
(let [[aa (-> (.getcwd os) (.split "/") (get -1) (.split " - "))]]
(if (= (len aa) 1)
(, "VA" (get aa 0))
(, (sp (get aa 0)) (sp (get aa 1))))))
(, (.strip (get aa 0)) (.strip (get aa 1))))))
; A long list of substitutions intended to turn a filename into a
; human-readable strategy. This operation is the result of weeks
@ -64,7 +68,6 @@
; filesystem access is a point of failure, but this is mostly
; reliable.
(defn tag-deriver [usefilenames]
(fn [mp3s]
(defn derive-tag [pos mp3]
@ -146,23 +149,39 @@
[artist
(if (.has_key opts "artist")
(get opts "artist")
(sfix loc_artist))]]
(sfix loc_artist))]
[format-string
(string.join ["id3v2 -T \"{}\""
"--album \"{}\""
"--artist \"{}\""
"--genre \"{}\""
"--song \"{}\""
"\"{}\""] " ")]]
(print genre album artist)))
(ap-each mp3s
(print (.format format-string (get it 5) album artist genre (get it 4) (get it 0))))))
(defmain [&rest args]
(try
(let [[optstringsshort
(string.join (ap-map (. it [0]) optlist) ":")]
(string.join (ap-map (+ (. it [0]) (cond [(. it [2]) ":"] [true ""])) optlist) "")]
[optstringslong
(list (ap-map (+ (. it [1]) (cond [(. it [2]) "="] [true ""])) optlist))]
[(, opt arg)
(getopt.getopt (slice args 1) optstringsshort optstringslong)]
[rationalize-options
(make-options-rationalizer optlist)]
[options
(ap-reduce (find-opt-reducer acc it) opt {})]]
(cond [(.has_key options "h") (print-help)]
[(.has_key options "v") (print-version)]
[true (suggest options)]))))
(ap-reduce (rationalize-options acc it) opt {})]]
(cond [(.has_key options "help") (print-help)]
[(.has_key options "version") (print-version)]
[true (suggest options)]))))

View File

@ -62,6 +62,35 @@ commands can be tweaked, and all of them override the techniques
This is probably completely idiosyncratic to the way I do things in my
own music archive, but as an exercise in writing Hy, it was fun.
\section{Options}
%%%%%%%%%%%%%%%%%
\begin{Description}
\item[\OptArg{--genre}{genre}] Set the genre manually from the command
line. This overrides any settings found in the ID3 tag. A short form
of this tag is ``-g''
\item[\OptArg{--album}{album}] Set the album manually from the command
line. This overrides any settings found in the ID3 tag. A short form
of this tag is ``-a''
\item[\OptArg{--artist}{artist}] Set the artist manually from the command
line. This overrides any settings found in the ID3 tag. A short form
of this tag is ``-r''
\item[\Opt{--usedir}] Use the directory name for artist and album
information. This overrides anything found in the ID3 tags. A short
form of this tag is ``-n''.
\item[\Opt{--usefilename}] Use the filename as the song title. This
overrides anything found in the ID3 tags. A short form of this tag is
``-t''.
\item[\Opt{--help}] Print a short help message. A short form of this
tag is ``-h''
\item[\Opt{--version}] Print the version information. A short form of this
tag is ``-v''
\section{Requirements}
%%%%%%%%%%%%%%%%%%%%%%