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