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 * Licensing

View File

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