Refactored CLI selection logic into a helper class.

This commit is contained in:
Jonathan Bernard 2016-03-10 10:47:26 -06:00
parent 1e03063400
commit b0532f6733

View File

@ -83,6 +83,10 @@ Configuration:
new ANSI().eraseLine(Erase.All).cursorPrevLine().eraseLine(Erase.All)
.cursorPrevLine().eraseLine(Erase.All).toString()
public final static modelClass = [
'album': Album, 'artist': Artist, 'bookmark': Bookmark,
'mediaFile': MediaFile, 'playlist': Playlist, 'tag': Tag ]
private int displayWidth = 79
private long msgTimeout
private ScrollText currentlyPlaying = new ScrollText(
@ -93,7 +97,7 @@ Configuration:
private SimpleDateFormat sdf = new SimpleDateFormat('EEE-HH-SSS')
/// Current play queue and selection data
def selection = [:]
Selection currentSelection = new Selection()
Playlist playQueue = library.save(new Playlist(
name: "CLI Queue ${sdf.format(new Date())}"))
Bookmark playBookmark
@ -246,10 +250,10 @@ Configuration:
logger.debug("command: $command")
switch(command?.toLowerCase()) {
case 'scan': return scanMediaLibrary()
case 'select': return processSelect(line)
case 'list': return processList(line)
case 'select': return processSelect(line, currentSelection)
case 'list': return processList(line, currentSelection)
case 'add': return processAdd(line)
case 'enque': return processEnque(line)
case 'enqueue': return processEnqueue(line)
case 'tag': return processTag(line)
case 'clear': return processClear(line)
case 'play': return line.size() == 0 ?
@ -296,10 +300,12 @@ Configuration:
dismissMsgDate = new Date(new Date().time + msgTimeout)
return library }
private def processSelect(LinkedList line) {
private def processSelect(LinkedList line, def sel = null) {
String option = line.poll()
boolean current = option == "current"
if (!sel) sel = new Selection()
def items
if (current) {
if (!curMediaFile) {
setErr "No media is currently playing."
@ -308,18 +314,21 @@ Configuration:
option = line.poll()
switch (option) {
case 'album':
return select(Album, getExactlyOne(Album,
library.getAlbumsWhere({ mediaFileId: curMediaFile.id})))
sel.album = ensureExactlyOne(
library.getAlbumsWhere({ mediaFileId: curMediaFile.id}))
return sel
case 'artist':
return selectOneMatch(library.getArtistsWhere({
mediaFileId: curMediaFile.id}))
sel.artist = ensureExactlyOne(
library.getArtistsWhere({ mediaFileId: curMediaFile.id}))
return sel
case 'playlist':
return selectOneMatch(playQueue)
sel.playlist = playQueue; return sel
case 'file':
return selectOneMatch(curMediaFile)
sel.mediaFile = curMediaFile; return sel
case 'tags':
return select(tags: library.getTagsWhere({
mediaFileId: curMediaFile.id}))
sel.tags = library.getTagsWhere({
mediaFileId: curMediaFile.id})
return sel
default:
setErr("Unrecognized option to ${promptStyle}select " +
"current${errorStyle}.")
@ -328,16 +337,15 @@ Configuration:
}
switch (option) {
case 'album': return selectOneMatch(
library.getByIdOrName(Album, line.join(' ')))
case 'artist': return selectOneMatch(
library.getByIdOrName(Artist, line.join(' ')))
case 'playlist': return selectOneMatch(
library.getByIdOrName(Playlist, line.join(' ')))
case 'file': return selectOneMatch(
library.getByIdOrName(MediaFile, line.join(' ')))
case 'tags': return select(tags:
line.map { library.getByIdOrName(Tag, it) }.filter().flatten())
case 'file': option = 'mediaFile'
case 'album': case 'artist': case 'playlist':
sel[option] = ensureExactlyOne(
library.getByIdOrName(modelClass[option], line.join(' ')))
return sel
case 'tags':
sel.tags = line.collect { library.getByIdOrName(Tag, it) }
.findAll().flatten()
return sel
default:
setErr("Unrecognized option to ${promptStyle}select${errorStyle}")
@ -390,7 +398,7 @@ Configuration:
switch(option) {
case 'queue': return library.removeAllFromPlaylist(playQueue.id)
case 'selected playlist':
if (!selection.playlist) {
if (!currentSelection.playlist) {
printLongMessage("No playlist currently selected.")
return null }
return library.removeAllFromPlaylist(selected.playlist.id)
@ -407,16 +415,19 @@ Configuration:
return null }
return library.removeAllFromPlaylist(playlist.id)
case 'selection':
currentSelection = new Selection()
break
default:
printLongMessage("Unrecognized option to the ${promptStyle}" +
"add${normalStyle} command. Use ${promptStyle}help clear" +
"clear${normalStyle} command. Use ${promptStyle}help clear" +
"${normalStyle} to see a list of valid options.")
return null
}
}
private def processList(LinkedList options) {
private def processList(LinkedList options, def selection) {
logger.debug("Listing things. Options: $options")
if (!selection) selection = new Selection()
def option = options.poll()
boolean all = option == 'all'
if (all) option = options.poll()
@ -424,6 +435,7 @@ Configuration:
logger.debug("Option: $option")
def list
switch(option) {
case 'albums':
if (all) list = library.getAlbums()
@ -435,7 +447,7 @@ Configuration:
String albumMatch = options?.join(" ")?.trim()
if (albumMatch) list = list.findAll { it.name =~ albumMatch }
printLongMessage(makeList(Album, list, all,
printLongMessage(makeList(selection, Album, list, all,
{ "${it.id}: ${it}" }))
break
@ -449,19 +461,20 @@ Configuration:
String artistMatch = options?.join(" ")?.trim()
if (artistMatch) list = list.findAll { it.name =~ artistMatch }
printLongMessage(makeList(Artist, list, all,
printLongMessage(makeList(selection, Artist, list, all,
{ "${it.id}: ${it.name}" }))
break
case 'files':
case 'selection':
if (all) list = library.getMediaFiles()
else list = getSelectedMediaFiles()
else list = selection.selectedFiles
if (selection.album) list = list.sort { it.trackNumber }
String mediaFileMatch = options?.join(" ")?.trim()
if (mediaFileMatch) list = list.findAll {
it.name =~ mediaFileMatch }
printLongMessage(makeList(MediaFile, list, all
printLongMessage(makeList(selection, MediaFile, list, all,
{ "${it.id}: ${it.trackNumber} - ${it.name}" }))
break
@ -473,7 +486,7 @@ Configuration:
String bookmarkMatch = options?.join(" ")?.trim()
if (boolmarkMatch)
list = list.findAll { it.name =~ bookmarkMatch }
printLongMessage(makeList(Bookmark, list, all,
printLongMessage(makeList(selection, Bookmark, list, all,
{ "${it.id}: ${it.name} ${it.userCreated ? '' : ' (auto)'}" }))
break
@ -487,7 +500,7 @@ Configuration:
String playlistMatch = options?.join(" ")?.trim()
if (playlistMatch)
list = list.findAll { it.name =~ playlistMatch }
printLongMessage(makeList(Playlist, list, all,
printLongMessage(makeList(selection, Playlist, list, all,
{ "${it.id}: ${it.name} ${it.userCreated ? '' : ' (auto)'}" }))
break
@ -500,7 +513,7 @@ Configuration:
String tagMatch = options?.join(" ")?.trim()
if (tagMatch) list = list.findAll { it.name =~ tagMatch }
printLongMessage(makeList(Tag, list, all,
printLongMessage(makeList(selection, Tag, list, all,
{ "${it.id}: ${it.name}" }))
break
@ -511,19 +524,16 @@ Configuration:
return null
}
resetStatus()
return list
}
public def unselect(Class modelClass) {
String key = uncapitalize(modelClass.simpleName)
this.selection[key] = null }
public def ensureExactlyOne(def matches) {
if (!matches) {
setErr("Nothing matches.");
return null }
String englishName = toEnglish(modelClass.simpleName)
String englishName = toEnglish(matches[0].class.simpleName)
if (matches.size() > 1) {
setErr("Multiple ${englishName}s match: " +
matches.collect { "${it.id}: ${it.name}" }.join(', '))
@ -534,11 +544,6 @@ Configuration:
public def getExactlyOne(Class modelClass, def criteria) {
return ensureExactlyOne(library.getByIdOrName(modelClass, criteria)) }
public def selectOneMatch(def matches) {
def match = ensureExactlyOne(matches)
if (match) selection[uncapitalize(match.class.simpleName)] = match
return match }
private void drawLeader(afterOutput = false) {
String leader = beforeLeader + getLeader() +
@ -581,16 +586,16 @@ Configuration:
status.text = errorStyle + errMsg
dismissMsgDate = new Date(new Date().time + msgTimeout) }
private String makeList(Class modelClass, def items,
boolean listAll = false, Closure toString = null) {
private String makeList(Selection selection, Class modelClass,
def items, boolean listAll = false, Closure toString = null) {
def result = new StringBuilder()
.append("--------------------\n${modelClass.simpleName}")
.append("--------------------\n${modelClass.simpleName}s")
if (!listAll && (selection.playlist || selection.artist ||
selection.mediaFile))
result.append("\n(for selection: ")
.append(describeSelection())
.append(selection.toString())
.append(normalStyle)
.append(")")
@ -600,49 +605,8 @@ Configuration:
return result.toString() }
private String describeSelection() {
StringBuilder s = new StringBuilder()
if (selection.playlist) s.append(playlistStyle)
.append(selection.playlist)
.append(normalStyle)
.append(": ")
if (selection.artist) s.append(artistStyle)
.append(selection.artist)
.append(normalStyle)
.append(" / ")
if (selection.album) s.append(albumStyle)
.append(selection.album)
.append(normalStyle)
.append(" / ")
if (selection.mediaFile) s.append(fileStyle)
.append(selection.mediaFile)
.append(normalStyle)
return s.toString()
}
private getSelectedMediaFiles() {
if (selection.mediaFile) return selection.mediaFile
return list = library.getMediaFilesWhere(
playlistId: selection?.playlist?.id,
artistId: selection?.artist?.id,
albumId: selection?.album?.id,
tags: selection?.tags) }
private String select(Map s) {
['artist', 'album', 'playlist', 'file', 'tags'].each {
this.selection[it] = s[it] }
resetStatus()
return selection
}
private String resetStatus() {
String s = describeSelection()
String s = currentSelection.toString()
if (s.size() == 0) status.text = "No current media selections."
else status.text = s
@ -657,4 +621,62 @@ Configuration:
private static String toEnglish(String modelName) {
return UPPERCASE_PATTERN.matcher(modelName).
replaceAll(/$1 $2/).toLowerCase() }
public class Selection {
Album album
Artist artist
MediaFile mediaFile
Playlist playlist
List<Tag> tags
public def unselect(Class modelClass) {
String key = uncapitalize(modelClass.simpleName)
def value = this[key]
this[key] = null
return value }
public Selection select(Map s) {
['artist', 'album', 'playlist', 'file', 'tags'].each {
this[it] = s[it] }
return this
}
public def select(def value) {
if (value) this[uncapitalize(match.class.simpleName)] = value
return value }
public List<MediaFile> getSelectedFiles() {
return library.getMediaFilesWhere(
playlistId: playlist?.id,
artistId: artist?.id,
albumId: album?.id,
tags: tags) }
public String toString() {
StringBuilder s = new StringBuilder()
if (playlist) s.append(playlistStyle)
.append(playlist)
.append(normalStyle)
.append(": ")
if (artist) s.append(artistStyle)
.append(artist)
.append(normalStyle)
.append(" / ")
if (album) s.append(albumStyle)
.append(album)
.append(normalStyle)
.append(" / ")
if (mediaFile) s.append(fileStyle)
.append(mediaFile)
.append(normalStyle)
return s.toString()
}
}
}