forked from openlp/openlp
Remote song search and go live beginnings
This commit is contained in:
parent
ae2d8c6961
commit
047287950c
@ -475,11 +475,18 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
translate('OpenLP.MediaManagerItem',
|
||||
'You must select one or more items to send live.'))
|
||||
else:
|
||||
log.debug(u'%s Live requested', self.plugin.name)
|
||||
serviceItem = self.buildServiceItem()
|
||||
if serviceItem:
|
||||
serviceItem.from_plugin = True
|
||||
self.parent.liveController.addServiceItem(serviceItem)
|
||||
self.goLive()
|
||||
|
||||
def goLive(self, item_id=None):
|
||||
log.debug(u'%s Live requested', self.plugin.name)
|
||||
item = None
|
||||
if item_id:
|
||||
item = QtGui.QListWidgetItem()
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(item_id))
|
||||
serviceItem = self.buildServiceItem(item)
|
||||
if serviceItem:
|
||||
serviceItem.from_plugin = True
|
||||
self.parent.liveController.addServiceItem(serviceItem)
|
||||
|
||||
def onAddClick(self):
|
||||
"""
|
||||
@ -573,3 +580,16 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
else:
|
||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
return item_id
|
||||
|
||||
def hasSearch(self):
|
||||
"""
|
||||
Returns whether this plugin supports the search method
|
||||
"""
|
||||
return False
|
||||
|
||||
def search(self, string):
|
||||
"""
|
||||
Performs a plugin specific search for items containing ``string``
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
u'Plugin.about needs to be defined by the plugin')
|
||||
|
@ -45,7 +45,7 @@ class PluginManager(object):
|
||||
"""
|
||||
The constructor for the plugin manager. Passes the controllers on to
|
||||
the plugins for them to interact with via their ServiceItems.
|
||||
|
||||
pluginmanager.py
|
||||
``plugin_dir``
|
||||
The directory to search for plugins.
|
||||
"""
|
||||
@ -211,3 +211,12 @@ class PluginManager(object):
|
||||
if plugin.isActive():
|
||||
plugin.finalise()
|
||||
log.info(u'Finalisation Complete for %s ' % plugin.name)
|
||||
|
||||
def get_plugin_by_name(self, name):
|
||||
"""
|
||||
Return the plugin which has a name with value ``name``
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
if plugin.name == name:
|
||||
return plugin
|
||||
return None
|
||||
|
@ -43,6 +43,7 @@
|
||||
<a href="#service-manager" data-role="button" data-icon="arrow-r" data-iconpos="right">Service Manager</a>
|
||||
<a href="#slide-controller" data-role="button" data-icon="arrow-r" data-iconpos="right">Slide Controller</a>
|
||||
<a href="#alerts" data-role="button" data-icon="arrow-r" data-iconpos="right">Alerts</a>
|
||||
<a href="#search" data-role="button" data-icon="arrow-r" data-iconpos="right">Search</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,7 +56,7 @@
|
||||
<ul data-role="listview" data-inset="true">
|
||||
</ul>
|
||||
</div>
|
||||
<div data-role="footer" data-theme="b" class="ui-bar">
|
||||
<div data-role="footer" data-position="fixed" data-theme="b" class="ui-bar">
|
||||
<a href="#" id="service-blank" data-role="button" data-icon="blank">Blank</a>
|
||||
<a href="#" id="service-unblank" data-role="button" data-icon="unblank">Unblank</a>
|
||||
<a href="#" id="service-refresh" data-role="button" data-icon="refresh">Refresh</a>
|
||||
@ -72,7 +73,7 @@
|
||||
<ul data-role="listview" data-inset="true">
|
||||
</ul>
|
||||
</div>
|
||||
<div data-role="footer" data-theme="b" class="ui-bar">
|
||||
<div data-role="footer" data-position="fixed" data-theme="b" class="ui-bar">
|
||||
<a href="#" id="controller-blank" data-role="button" data-icon="blank">Blank</a>
|
||||
<a href="#" id="controller-unblank" data-role="button" data-icon="unblank">Unblank</a>
|
||||
<a href="#" id="controller-refresh" data-role="button" data-icon="refresh">Refresh</a>
|
||||
@ -93,5 +94,19 @@
|
||||
<a href="#" id="alert-submit" data-role="button">Show Alert</a>
|
||||
</div>
|
||||
</div>
|
||||
<div data-role="page" id="search">
|
||||
<div data-role="header">
|
||||
<a href="#" data-rel="back" data-icon="arrow-l">Back</a>
|
||||
<h1>Search</h1>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
<div data-role="fieldcontain">
|
||||
<label for="search-text">Search:</label>
|
||||
<input type="text" name="search-text" id="search-text" value="" />
|
||||
</div>
|
||||
<a href="#" id="search-submit" data-role="button">Search</a>
|
||||
<ul data-role="listview" data-inset="true">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -189,7 +189,43 @@ window.OpenLP = {
|
||||
}
|
||||
);
|
||||
return false;
|
||||
},
|
||||
search: function (event) {
|
||||
var text = JSON.stringify({"request": {"text": $("#search-text").val()}});
|
||||
$.getJSON(
|
||||
"/api/Songs/search",
|
||||
{"data": text},
|
||||
function (data, status) {
|
||||
var ul = $("#search > div[data-role=content] > ul[data-role=listview]");
|
||||
ul.html("");
|
||||
if (data.results.items.length == 0) {
|
||||
var li = $("<li data-icon=\"false\">").text('No results');
|
||||
ul.append(li);
|
||||
}
|
||||
else {
|
||||
$.each(data.results.items, function (idx, value) {
|
||||
var li = $("<li data-icon=\"false\">").append(
|
||||
$("<a href=\"#\">").attr("value", value[0]).text(value[1]));
|
||||
li.children("a").click(OpenLP.goLive);
|
||||
ul.append(li);
|
||||
});
|
||||
}
|
||||
ul.listview("refresh");
|
||||
}
|
||||
);
|
||||
return false;
|
||||
},
|
||||
goLive: function (event) {
|
||||
var slide = OpenLP.getElement(event);
|
||||
var id = slide.attr("value");
|
||||
var text = JSON.stringify({"request": {"id": id}});
|
||||
$.getJSON(
|
||||
"/api/Songs/live",
|
||||
{"data": text})
|
||||
window.location.replace('/#slide-controller');
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
// Service Manager
|
||||
$("#service-manager").live("pagebeforeshow", OpenLP.loadService);
|
||||
@ -207,6 +243,8 @@ $("#controller-blank").live("click", OpenLP.blankDisplay);
|
||||
$("#controller-unblank").live("click", OpenLP.unblankDisplay);
|
||||
// Alerts
|
||||
$("#alert-submit").live("click", OpenLP.showAlert);
|
||||
// Search
|
||||
$("#search-submit").live("click", OpenLP.search);
|
||||
// Poll the server twice a second to get any updates.
|
||||
$.ajaxSetup({ cache: false });
|
||||
setInterval("OpenLP.pollServer();", 500);
|
||||
|
@ -250,7 +250,10 @@ class HttpConnection(object):
|
||||
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
|
||||
(r'^/api/service/(.*)$', self.service),
|
||||
(r'^/api/display/(hide|show)$', self.display),
|
||||
(r'^/api/alert$', self.alert)
|
||||
(r'^/api/alert$', self.alert),
|
||||
(r'^/api/plugin/(search)$', self.plugin),
|
||||
(r'^/api/(.*)/search$', self.search),
|
||||
(r'^/api/(.*)/live$', self.go_live)
|
||||
]
|
||||
QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'readyRead()'),
|
||||
self.ready_read)
|
||||
@ -443,6 +446,49 @@ class HttpConnection(object):
|
||||
return HttpResponse(json.dumps({u'results': {u'success': True}}),
|
||||
{u'Content-Type': u'application/json'})
|
||||
|
||||
def plugin(self, action):
|
||||
"""
|
||||
Return plugin related actions
|
||||
|
||||
``action`` - The action to perform
|
||||
if 'search' return a list of plugin names which support search
|
||||
"""
|
||||
if action == u'search':
|
||||
searches = []
|
||||
for plugin in self.parent.parent.pluginManager.plugins:
|
||||
media_item = plugin.mediaItem
|
||||
if media_item and media_item.hasSearch():
|
||||
searches.append(plugin.Name)
|
||||
return HttpResponse(
|
||||
json.dumps({u'results': {u'items': searches}}),
|
||||
{u'Content-Type': u'application/json'})
|
||||
|
||||
def search(self, type):
|
||||
"""
|
||||
Return a list of items that match the search text
|
||||
|
||||
``type``
|
||||
The plugin name to search in.
|
||||
"""
|
||||
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
|
||||
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type)
|
||||
media_item = plugin.mediaItem
|
||||
if media_item and media_item.hasSearch():
|
||||
results = media_item.search(text)
|
||||
return HttpResponse(
|
||||
json.dumps({u'results': {u'items': results}}),
|
||||
{u'Content-Type': u'application/json'})
|
||||
|
||||
def go_live(self, type):
|
||||
"""
|
||||
Go live on an item of type ``type``.
|
||||
"""
|
||||
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
|
||||
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type)
|
||||
media_item = plugin.mediaItem
|
||||
if media_item:
|
||||
media_item.goLive(id)
|
||||
|
||||
def send_response(self, response):
|
||||
http = u'HTTP/1.1 %s\r\n' % response.code
|
||||
for header, value in response.headers.iteritems():
|
||||
|
@ -171,11 +171,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
search_type = self.searchTextEdit.currentSearchType()
|
||||
if search_type == SongSearch.Entire:
|
||||
log.debug(u'Entire Song Search')
|
||||
search_results = self.parent.manager.get_all_objects(Song,
|
||||
or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ',
|
||||
search_keywords.lower()) + u'%'),
|
||||
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'),
|
||||
Song.comments.like(u'%' + search_keywords.lower() + u'%')))
|
||||
search_results = self.searchEntire(search_keywords)
|
||||
self.displayResultsSong(search_results)
|
||||
elif search_type == SongSearch.Titles:
|
||||
log.debug(u'Titles Search')
|
||||
@ -201,6 +197,13 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.displayResultsSong(search_results)
|
||||
check_search_result(self.listView, search_results)
|
||||
|
||||
def searchEntire(self, search_keywords):
|
||||
return self.parent.manager.get_all_objects(Song,
|
||||
or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ',
|
||||
search_keywords.lower()) + u'%'),
|
||||
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'),
|
||||
Song.comments.like(u'%' + search_keywords.lower() + u'%')))
|
||||
|
||||
def onSongListLoad(self):
|
||||
"""
|
||||
Handle the exit from the edit dialog and trigger remote updates
|
||||
@ -217,7 +220,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
# Push edits to the service manager to update items
|
||||
if self.editItem and self.updateServiceOnEdit and \
|
||||
not self.remoteTriggered:
|
||||
item = self.buildServiceItem(self.editItem)
|
||||
item_id = _getIdOfItemToGenerate(self.editItem)
|
||||
item = self.buildServiceItem(item_id)
|
||||
self.parent.serviceManager.replaceServiceItem(item)
|
||||
self.onRemoteEditClear()
|
||||
self.onSearchTextButtonClick()
|
||||
@ -475,3 +479,19 @@ class SongMediaItem(MediaManagerItem):
|
||||
"""
|
||||
return locale.strcoll(unicode(song_1.title.lower()),
|
||||
unicode(song_2.title.lower()))
|
||||
|
||||
def hasSearch(self):
|
||||
"""
|
||||
Returns whether this plugin supports the search method
|
||||
"""
|
||||
return True
|
||||
|
||||
def search(self, string):
|
||||
"""
|
||||
Search for some songs
|
||||
"""
|
||||
search_results = self.searchEntire(string)
|
||||
results = []
|
||||
for song in search_results:
|
||||
results.append([song.id, song.title])
|
||||
return results
|
||||
|
@ -268,4 +268,3 @@ class SongsPlugin(Plugin):
|
||||
action_list.remove_action(self.songExportItem, UiStrings().Export)
|
||||
action_list.remove_action(self.toolsReindexItem, UiStrings().Tools)
|
||||
Plugin.finalise(self)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user