+(defun emus-get-audio-files ()
+ "Get all mp3 files in main emus directory."
+ (directory-files-recursively emus-directory ".*\\.mp3"))
+
+(defun emus-make-track (artist album title filename &optional pos)
+ "Create an object representing an emus track.
+ARTIST, ALBUM and TITLE are used to describe the track, FILENAME
+refers to the mp3 file containing the track. If non-nil, POS
+specifies the position of the record representing this track in the
+emus browser buffer."
+ (vector artist album title filename pos))
+
+(defun emus-track-artist (track)
+ "The artist corresponding to TRACK."
+ (elt track 0))
+
+(defun emus-track-album (track)
+ "The album corresponding to TRACK."
+ (elt track 1))
+
+(defun emus-track-title (track)
+ "The title of TRACK."
+ (elt track 2))
+
+(defun emus-track-file (track)
+ "The mp3 file corresponding to TRACK."
+ (elt track 3))
+
+(defun emus-track-browser-pos (track)
+ "The location of the browser buffer record corresponding to TRACK."
+ (elt track 4))
+
+(defun emus-set-track-browser-pos (track pos)
+ "Set the location of the browser buffer record corresponding to TRACK to POS."
+ (aset track 4 pos))
+
+(defun emus--load-library (then)
+ "Initialize the emus track library.
+Once the library is initialized, the function THEN is called."
+ (unless emus--proc-in-use
+ (setq emus--proc-in-use t)
+ (emus--suspend-cp)
+ (setq emus-state 'stopped)
+ (let ((proc (emus-get-process))
+ (tagstr "")
+ (filenames (emus-get-audio-files)))
+ (setq emus-tracks nil)
+ (set-process-filter proc (lambda (proc string)
+ (setq tagstr (concat tagstr string))
+ (when (string-suffix-p "@P 1\n" string)
+ (add-to-list 'emus-tracks
+ (emus--make-track-from-tagstr (car filenames)
+ tagstr))
+ (setq tagstr "")
+ (setq filenames (cdr filenames))
+ (if filenames
+ (emus--send-cmd-raw "lp" (car filenames))
+ (set-process-filter proc nil)
+ (setq emus-tracks (reverse emus-tracks))
+ (emus--sort-tracks)
+ (unless emus-current-track
+ (setq emus-current-track (car emus-tracks)))
+ (funcall then)
+ (emus--resume-cp)
+ (setq emus--proc-in-use nil)))))
+ (emus--send-cmd-raw "lp" (car filenames)))))
+
+(defun emus--make-track-from-tagstr (filename tagstr)
+ "Parse TAGSTR to populate the fields of a track corresponding to FILENAME."
+ (let ((artist "")
+ (album "")
+ (title ""))
+ (dolist (line (split-string tagstr "\n"))
+ (let ((found-artist (elt (split-string line "@I ID3v2.artist:") 1))
+ (found-album (elt (split-string line "@I ID3v2.album:") 1))
+ (found-title (elt (split-string line "@I ID3v2.title:") 1)))
+ (cond
+ (found-artist (setq artist found-artist))
+ (found-album (setq album found-album))
+ (found-title (setq title found-title)))))
+ (emus-make-track artist album title filename nil)))
+
+(defun emus--sort-tracks ()
+ "Sort the library tracks according to artist and album.
+Leaves the track titles unsorted, so they will appear in the order specified
+by the filesystem."
+ (sort emus-tracks
+ (lambda (r1 r2)
+ (let ((artist1 (emus-track-artist r1))
+ (artist2 (emus-track-artist r2)))
+ (if (string= artist1 artist2)
+ (let ((album1 (emus-track-album r1))
+ (album2 (emus-track-album r2)))
+ (string< album1 album2))
+ (string< artist1 artist2))))))
+
+(defmacro emus--with-library (&rest body)
+ "Evaluate BODY with the library initialized."
+ `(if emus-tracks
+ (progn ,@body)
+ (emus--load-library
+ (lambda () ,@body))))