Refactored CLI selection logic into a helper class.
This commit is contained in:
parent
1e03063400
commit
b0532f6733
@ -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()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user