forked from openlp/openlp
More updates
This commit is contained in:
parent
3ae188c287
commit
a0a2e5efbc
@ -107,7 +107,7 @@ class SongFormat(object):
|
||||
Name of the format, e.g. ``'OpenLyrics'``
|
||||
|
||||
``'prefix'``
|
||||
Prefix for Qt objects. Use mixedCase, e.g. ``'openLyrics'``
|
||||
Prefix for Qt objects. Use mixedCase, e.g. ``'open_lyrics'``
|
||||
See ``SongImportForm.add_file_select_item()``
|
||||
|
||||
Optional attributes for each song format:
|
||||
@ -185,7 +185,7 @@ class SongFormat(object):
|
||||
OpenLyrics: {
|
||||
'class': OpenLyricsImport,
|
||||
'name': 'OpenLyrics',
|
||||
'prefix': 'openLyrics',
|
||||
'prefix': 'open_lyrics',
|
||||
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'),
|
||||
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song')
|
||||
},
|
||||
|
@ -97,7 +97,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
def add_end_header_bar(self):
|
||||
self.toolbar.addSeparator()
|
||||
## Song Maintenance Button ##
|
||||
self.maintenanceAction = self.toolbar.add_toolbar_action('maintenanceAction',
|
||||
self.maintenance_action = self.toolbar.add_toolbar_action('maintenance_action',
|
||||
icon=':/songs/song_maintenance.png',
|
||||
triggers=self.on_song_maintenance_click)
|
||||
self.add_search_to_toolbar()
|
||||
@ -105,13 +105,13 @@ class SongMediaItem(MediaManagerItem):
|
||||
Registry().register_function('songs_load_list', self.on_song_list_load)
|
||||
Registry().register_function('songs_preview', self.on_preview_click)
|
||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('cleared()'), self.on_clear_text_button_click)
|
||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('searchTypeChanged(int)'),
|
||||
self.on_search_text_button_clicked)
|
||||
QtCore.QObject.connect(
|
||||
self.search_text_edit, QtCore.SIGNAL('searchTypeChanged(int)'), self.on_search_text_button_clicked)
|
||||
|
||||
def add_custom_context_actions(self):
|
||||
create_widget_action(self.list_view, separator=True)
|
||||
create_widget_action(self.list_view,
|
||||
text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png',
|
||||
create_widget_action(
|
||||
self.list_view, text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png',
|
||||
triggers=self.on_clone_click)
|
||||
|
||||
def on_focus(self):
|
||||
@ -123,14 +123,14 @@ class SongMediaItem(MediaManagerItem):
|
||||
"""
|
||||
log.debug('config_updated')
|
||||
self.search_as_you_type = Settings().value(self.settings_section + '/search as type')
|
||||
self.updateServiceOnEdit = Settings().value(self.settings_section + '/update service on edit')
|
||||
self.addSongFromService = Settings().value(self.settings_section + '/add song from service',)
|
||||
self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit')
|
||||
self.add_song_from_service = Settings().value(self.settings_section + '/add song from service',)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.search_text_label.setText('%s:' % UiStrings().Search)
|
||||
self.search_text_button.setText(UiStrings().Search)
|
||||
self.maintenanceAction.setText(SongStrings.SongMaintenance)
|
||||
self.maintenanceAction.setToolTip(translate('SongsPlugin.MediaItem',
|
||||
self.maintenance_action.setText(SongStrings.SongMaintenance)
|
||||
self.maintenance_action.setToolTip(translate('SongsPlugin.MediaItem',
|
||||
'Maintain the lists of authors, topics and books.'))
|
||||
|
||||
def initialise(self):
|
||||
@ -139,7 +139,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
"""
|
||||
self.song_maintenance_form = SongMaintenanceForm(self.plugin.manager, self)
|
||||
self.edit_song_form = EditSongForm(self, self.main_window, self.plugin.manager)
|
||||
self.openLyrics = OpenLyrics(self.plugin.manager)
|
||||
self.open_lyrics = OpenLyrics(self.plugin.manager)
|
||||
self.search_text_edit.set_search_types([
|
||||
(SongSearch.Entire, ':/songs/song_search_all.png',
|
||||
translate('SongsPlugin.MediaItem', 'Entire Song'),
|
||||
@ -154,8 +154,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
translate('SongsPlugin.MediaItem', 'Search Authors...')),
|
||||
(SongSearch.Books, ':/songs/song_book_edit.png', SongStrings.SongBooks,
|
||||
translate('SongsPlugin.MediaItem', 'Search Song Books...')),
|
||||
(SongSearch.Themes, ':/slides/slide_theme.png',
|
||||
UiStrings().Themes, UiStrings().SearchThemes)
|
||||
(SongSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)
|
||||
])
|
||||
self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section))
|
||||
self.config_update()
|
||||
@ -172,64 +171,65 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.display_results_song(search_results)
|
||||
elif search_type == SongSearch.Titles:
|
||||
log.debug('Titles Search')
|
||||
search_results = self.plugin.manager.get_all_objects(Song,
|
||||
Song.search_title.like('%' + clean_string(search_keywords) + '%'))
|
||||
search_string = '%' + clean_string(search_keywords) + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(Song, Song.search_title.like(search_string))
|
||||
self.display_results_song(search_results)
|
||||
elif search_type == SongSearch.Lyrics:
|
||||
log.debug('Lyrics Search')
|
||||
search_results = self.plugin.manager.get_all_objects(Song,
|
||||
Song.search_lyrics.like('%' + clean_string(search_keywords) + '%'))
|
||||
search_string = '%' + clean_string(search_keywords) + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(Song, Song.search_lyrics.like(search_string))
|
||||
self.display_results_song(search_results)
|
||||
elif search_type == SongSearch.Authors:
|
||||
log.debug('Authors Search')
|
||||
search_results = self.plugin.manager.get_all_objects(Author,
|
||||
Author.display_name.like('%' + search_keywords + '%'), Author.display_name.asc())
|
||||
search_string = '%' + search_keywords + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(
|
||||
Author, Author.display_name.like(search_string), Author.display_name.asc())
|
||||
self.display_results_author(search_results)
|
||||
elif search_type == SongSearch.Books:
|
||||
log.debug('Books Search')
|
||||
search_results = self.plugin.manager.get_all_objects(Book,
|
||||
Book.name.like('%' + search_keywords + '%'), Book.name.asc())
|
||||
search_string = '%' + search_keywords + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(Book, Book.name.like(search_string), Book.name.asc())
|
||||
song_number = False
|
||||
if not search_results:
|
||||
search_keywords = search_keywords.rpartition(' ')
|
||||
search_string = '%' + search_keywords + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(Book,
|
||||
Book.name.like('%' + search_keywords[0] + '%'), Book.name.asc())
|
||||
Book.name.like(search_string), Book.name.asc())
|
||||
song_number = re.sub(r'[^0-9]', '', search_keywords[2])
|
||||
self.display_results_book(search_results, song_number)
|
||||
elif search_type == SongSearch.Themes:
|
||||
log.debug('Theme Search')
|
||||
search_results = self.plugin.manager.get_all_objects(Song,
|
||||
Song.theme_name.like('%' + search_keywords + '%'))
|
||||
search_string = '%' + search_keywords + '%'
|
||||
search_results = self.plugin.manager.get_all_objects(Song, Song.theme_name.like(search_string))
|
||||
self.display_results_song(search_results)
|
||||
self.check_search_result()
|
||||
|
||||
def search_entire(self, search_keywords):
|
||||
return self.plugin.manager.get_all_objects(Song,
|
||||
or_(Song.search_title.like('%' + clean_string(search_keywords) + '%'),
|
||||
Song.search_lyrics.like('%' + clean_string(search_keywords) + '%'),
|
||||
Song.comments.like('%' + search_keywords.lower() + '%')))
|
||||
search_string = '%' + clean_string(search_keywords) + '%'
|
||||
return self.plugin.manager.get_all_objects(
|
||||
Song, or_(Song.search_title.like(search_string), Song.search_lyrics.like(search_string),
|
||||
Song.comments.like(search_string)))
|
||||
|
||||
def on_song_list_load(self):
|
||||
"""
|
||||
Handle the exit from the edit dialog and trigger remote updates
|
||||
of songs
|
||||
Handle the exit from the edit dialog and trigger remote updates of songs
|
||||
"""
|
||||
log.debug('on_song_list_load - start')
|
||||
# Called to redisplay the song list screen edit from a search or from the exit of the Song edit dialog. If
|
||||
# remote editing is active Trigger it and clean up so it will not update again. Push edits to the service
|
||||
# manager to update items
|
||||
if self.edit_item and self.updateServiceOnEdit and not self.remote_triggered:
|
||||
if self.edit_item and self.update_service_on_edit and not self.remote_triggered:
|
||||
item = self.build_service_item(self.edit_item)
|
||||
self.service_manager.replace_service_item(item)
|
||||
self.on_search_text_button_clicked()
|
||||
log.debug('on_song_list_load - finished')
|
||||
|
||||
def display_results_song(self, searchresults):
|
||||
def display_results_song(self, search_results):
|
||||
log.debug('display results Song')
|
||||
self.save_auto_select_id()
|
||||
self.list_view.clear()
|
||||
searchresults.sort(key=lambda song: song.sort_key)
|
||||
for song in searchresults:
|
||||
search_results.sort(key=lambda song: song.sort_key)
|
||||
for song in search_results:
|
||||
# Do not display temporary songs
|
||||
if song.temporary:
|
||||
continue
|
||||
@ -244,10 +244,10 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.list_view.setCurrentItem(song_name)
|
||||
self.auto_select_id = -1
|
||||
|
||||
def display_results_author(self, searchresults):
|
||||
def display_results_author(self, search_results):
|
||||
log.debug('display results Author')
|
||||
self.list_view.clear()
|
||||
for author in searchresults:
|
||||
for author in search_results:
|
||||
for song in author.songs:
|
||||
# Do not display temporary songs
|
||||
if song.temporary:
|
||||
@ -257,12 +257,11 @@ class SongMediaItem(MediaManagerItem):
|
||||
song_name.setData(QtCore.Qt.UserRole, song.id)
|
||||
self.list_view.addItem(song_name)
|
||||
|
||||
def display_results_book(self, searchresults, song_number=False):
|
||||
def display_results_book(self, search_results, song_number=False):
|
||||
log.debug('display results Book')
|
||||
self.list_view.clear()
|
||||
for book in searchresults:
|
||||
songs = sorted(book.songs, key=lambda song:
|
||||
int(re.match(r'[0-9]+', '0' + song.song_number).group()))
|
||||
for book in search_results:
|
||||
songs = sorted(book.songs, key=lambda song: int(re.match(r'[0-9]+', '0' + song.song_number).group()))
|
||||
for song in songs:
|
||||
# Do not display temporary songs
|
||||
if song.temporary:
|
||||
@ -305,9 +304,9 @@ class SongMediaItem(MediaManagerItem):
|
||||
Registry().execute('songs_load_list')
|
||||
|
||||
def on_export_click(self):
|
||||
if not hasattr(self, 'exportWizard'):
|
||||
self.exportWizard = SongExportForm(self, self.plugin)
|
||||
self.exportWizard.exec_()
|
||||
if not hasattr(self, 'export_wizard'):
|
||||
self.export_wizard = SongExportForm(self, self.plugin)
|
||||
self.export_wizard.exec_()
|
||||
|
||||
def on_new_click(self):
|
||||
log.debug('on_new_click')
|
||||
@ -362,8 +361,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
"""
|
||||
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
||||
items = self.list_view.selectedIndexes()
|
||||
if QtGui.QMessageBox.question(self,
|
||||
UiStrings().ConfirmDelete,
|
||||
if QtGui.QMessageBox.question(
|
||||
self, UiStrings().ConfirmDelete,
|
||||
translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '',
|
||||
QtCore.QCoreApplication.CodecForTr, len(items)),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||
@ -388,17 +387,23 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.edit_item = self.list_view.currentItem()
|
||||
item_id = self.edit_item.data(QtCore.Qt.UserRole)
|
||||
old_song = self.plugin.manager.get_object(Song, item_id)
|
||||
song_xml = self.openLyrics.song_to_xml(old_song)
|
||||
new_song = self.openLyrics.xml_to_song(song_xml)
|
||||
new_song.title = '%s <%s>' % (new_song.title,
|
||||
translate('SongsPlugin.MediaItem', 'copy', 'For song cloning'))
|
||||
song_xml = self.open_lyrics.song_to_xml(old_song)
|
||||
new_song = self.open_lyrics.xml_to_song(song_xml)
|
||||
new_song.title = '%s <%s>' % \
|
||||
(new_song.title, translate('SongsPlugin.MediaItem', 'copy', 'For song cloning'))
|
||||
self.plugin.manager.save_object(new_song)
|
||||
self.on_song_list_load()
|
||||
|
||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
||||
remote=False, context=ServiceItemContext.Service):
|
||||
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
|
||||
context=ServiceItemContext.Service):
|
||||
"""
|
||||
Generate the slide data. Needs to be implemented by the plugin.
|
||||
|
||||
:param service_item: The service item to be built on
|
||||
:param item: The Song item to be used
|
||||
:param xml_version: The xml version (not used)
|
||||
:param remote: Triggered from remote
|
||||
:param context: Why is it being generated
|
||||
"""
|
||||
log.debug('generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song))
|
||||
item_id = self._get_id_of_item_to_generate(item, self.remote_song)
|
||||
@ -411,7 +416,6 @@ class SongMediaItem(MediaManagerItem):
|
||||
song = self.plugin.manager.get_object(Song, item_id)
|
||||
service_item.theme = song.theme_name
|
||||
service_item.edit_id = item_id
|
||||
if song.lyrics.startswith('<?xml version='):
|
||||
verse_list = SongXML().get_verses(song.lyrics)
|
||||
# no verse list or only 1 space (in error)
|
||||
verse_tags_translated = False
|
||||
@ -438,8 +442,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
if not order:
|
||||
break
|
||||
for verse in verse_list:
|
||||
if verse[0]['type'][0].lower() == order[0] and (verse[0]['label'].lower() == order[1:] or \
|
||||
not order[1:]):
|
||||
if verse[0]['type'][0].lower() == \
|
||||
order[0] and (verse[0]['label'].lower() == order[1:] or not order[1:]):
|
||||
if verse_tags_translated:
|
||||
verse_index = VerseType.from_translated_tag(verse[0]['type'])
|
||||
else:
|
||||
@ -447,14 +451,10 @@ class SongMediaItem(MediaManagerItem):
|
||||
verse_tag = VerseType.translated_tags[verse_index]
|
||||
verse_def = '%s%s' % (verse_tag, verse[0]['label'])
|
||||
service_item.add_from_text(verse[1], verse_def)
|
||||
else:
|
||||
verses = song.lyrics.split('\n\n')
|
||||
for slide in verses:
|
||||
service_item.add_from_text(str(slide))
|
||||
service_item.title = song.title
|
||||
author_list = self.generate_footer(service_item, song)
|
||||
service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)}
|
||||
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
||||
service_item.xml_version = self.open_lyrics.song_to_xml(song)
|
||||
# Add the audio file to the service item.
|
||||
if song.media_files:
|
||||
service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
|
||||
@ -466,11 +466,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
Generates the song footer based on a song and adds details to a service item.
|
||||
author_list is only required for initial song generation.
|
||||
|
||||
``item``
|
||||
The service item to be amended
|
||||
|
||||
``song``
|
||||
The song to be used to generate the footer
|
||||
:param item: The service item to be amended
|
||||
:param song: The song to be used to generate the footer
|
||||
"""
|
||||
author_list = [str(author.display_name) for author in song.authors]
|
||||
item.audit = [
|
||||
@ -481,8 +478,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
item.raw_footer.append(create_separated_list(author_list))
|
||||
item.raw_footer.append(song.copyright)
|
||||
if Settings().value('core/ccli number'):
|
||||
item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
||||
Settings().value('core/ccli number'))
|
||||
item.raw_footer.append(translate('SongsPlugin.MediaItem',
|
||||
'CCLI License: ') + Settings().value('core/ccli number'))
|
||||
return author_list
|
||||
|
||||
def service_load(self, item):
|
||||
@ -500,8 +497,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(' ',
|
||||
item.data_string['title'].strip()) + '@').strip().lower(), Song.search_title.asc())
|
||||
else:
|
||||
search_results = self.plugin.manager.get_all_objects(Song,
|
||||
Song.search_title == item.data_string['title'], Song.search_title.asc())
|
||||
search_results = self.plugin.manager.get_all_objects(
|
||||
Song, Song.search_title == item.data_string['title'], Song.search_title.asc())
|
||||
edit_id = 0
|
||||
add_song = True
|
||||
if search_results:
|
||||
@ -521,16 +518,16 @@ class SongMediaItem(MediaManagerItem):
|
||||
# If there's any backing tracks, copy them over.
|
||||
if item.background_audio:
|
||||
self._update_background_audio(song, item)
|
||||
if add_song and self.addSongFromService:
|
||||
song = self.openLyrics.xml_to_song(item.xml_version)
|
||||
if add_song and self.add_song_from_service:
|
||||
song = self.open_lyrics.xml_to_song(item.xml_version)
|
||||
# If there's any backing tracks, copy them over.
|
||||
if item.background_audio:
|
||||
self._update_background_audio(song, item)
|
||||
editId = song.id
|
||||
edit_id = song.id
|
||||
self.on_search_text_button_clicked()
|
||||
elif add_song and not self.addSongFromService:
|
||||
elif add_song and not self.add_song_from_service:
|
||||
# Make sure we temporary import formatting tags.
|
||||
song = self.openLyrics.xml_to_song(item.xml_version, True)
|
||||
song = self.open_lyrics.xml_to_song(item.xml_version, True)
|
||||
# If there's any backing tracks, copy them over.
|
||||
if item.background_audio:
|
||||
self._update_background_audio(song, item)
|
||||
@ -540,9 +537,11 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.generate_footer(item, song)
|
||||
return item
|
||||
|
||||
def search(self, string, showError):
|
||||
def search(self, string, show_error):
|
||||
"""
|
||||
Search for some songs
|
||||
:param string: The string to show
|
||||
:param show_error: Is this an error?
|
||||
"""
|
||||
search_results = self.search_entire(string)
|
||||
return [[song.id, song.title] for song in search_results]
|
||||
|
@ -37,6 +37,7 @@ from openlp.plugins.songs.lib.songimport import SongImport
|
||||
|
||||
VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E']
|
||||
|
||||
|
||||
class MediaShoutImport(SongImport):
|
||||
"""
|
||||
The :class:`MediaShoutImport` class provides the ability to import the
|
||||
@ -53,38 +54,34 @@ class MediaShoutImport(SongImport):
|
||||
Receive a single file to import.
|
||||
"""
|
||||
try:
|
||||
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};'
|
||||
'DBQ=%s;PWD=6NOZ4eHK7k' % self.import_source)
|
||||
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=6NOZ4eHK7k' %
|
||||
self.import_source)
|
||||
except:
|
||||
# Unfortunately no specific exception type
|
||||
self.log_error(self.import_source,
|
||||
translate('SongsPlugin.MediaShoutImport', 'Unable to open the MediaShout database.'))
|
||||
self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport',
|
||||
'Unable to open the MediaShout database.'))
|
||||
return
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT Record, Title, Author, Copyright, '
|
||||
'SongID, CCLI, Notes FROM Songs ORDER BY Title')
|
||||
cursor.execute('SELECT Record, Title, Author, Copyright, SongID, CCLI, Notes FROM Songs ORDER BY Title')
|
||||
songs = cursor.fetchall()
|
||||
self.import_wizard.progress_bar.setMaximum(len(songs))
|
||||
for song in songs:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
cursor.execute('SELECT Type, Number, Text FROM Verses '
|
||||
'WHERE Record = %s ORDER BY Type, Number' % song.Record)
|
||||
cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = %s ORDER BY Type, Number'
|
||||
% song.Record)
|
||||
verses = cursor.fetchall()
|
||||
cursor.execute('SELECT Type, Number, POrder FROM PlayOrder '
|
||||
'WHERE Record = %s ORDER BY POrder' % song.Record)
|
||||
cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = %s ORDER BY POrder' % song.Record)
|
||||
verse_order = cursor.fetchall()
|
||||
cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes '
|
||||
'ON SongThemes.ThemeId = Themes.ThemeId '
|
||||
cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId '
|
||||
'WHERE SongThemes.Record = %s' % song.Record)
|
||||
topics = cursor.fetchall()
|
||||
cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups '
|
||||
'ON SongGroups.GroupId = Groups.GroupId '
|
||||
cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId '
|
||||
'WHERE SongGroups.Record = %s' % song.Record)
|
||||
topics += cursor.fetchall()
|
||||
self.processSong(song, verses, verse_order, topics)
|
||||
self.process_song(song, verses, verse_order, topics)
|
||||
|
||||
def processSong(self, song, verses, verse_order, topics):
|
||||
def process_song(self, song, verses, verse_order, topics):
|
||||
"""
|
||||
Create the song, i.e. title, verse etc.
|
||||
"""
|
||||
|
@ -45,6 +45,7 @@ from .songimport import SongImport
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenLPSongImport(SongImport):
|
||||
"""
|
||||
The :class:`OpenLPSongImport` class provides OpenLP with the ability to
|
||||
@ -54,20 +55,17 @@ class OpenLPSongImport(SongImport):
|
||||
"""
|
||||
Initialise the import.
|
||||
|
||||
``manager``
|
||||
The song manager for the running OpenLP installation.
|
||||
|
||||
``source_db``
|
||||
The database providing the data to import.
|
||||
:param manager: The song manager for the running OpenLP installation.
|
||||
:param kwargs: The database providing the data to import.
|
||||
"""
|
||||
SongImport.__init__(self, manager, **kwargs)
|
||||
self.sourceSession = None
|
||||
self.source_session = None
|
||||
|
||||
def do_import(self, progressDialog=None):
|
||||
def do_import(self, progress_dialog=None):
|
||||
"""
|
||||
Run the import for an OpenLP version 2 song database.
|
||||
|
||||
``progressDialog``
|
||||
``progress_dialog``
|
||||
The QProgressDialog used when importing songs from the FRW.
|
||||
"""
|
||||
|
||||
@ -77,28 +75,24 @@ class OpenLPSongImport(SongImport):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OldBook(BaseModel):
|
||||
"""
|
||||
Book model
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OldMediaFile(BaseModel):
|
||||
"""
|
||||
MediaFile model
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OldSong(BaseModel):
|
||||
"""
|
||||
Song model
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OldTopic(BaseModel):
|
||||
"""
|
||||
Topic model
|
||||
@ -107,15 +101,15 @@ class OpenLPSongImport(SongImport):
|
||||
|
||||
# Check the file type
|
||||
if not self.import_source.endswith('.sqlite'):
|
||||
self.log_error(self.import_source,
|
||||
translate('SongsPlugin.OpenLPSongImport', 'Not a valid OpenLP 2.0 song database.'))
|
||||
self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport',
|
||||
'Not a valid OpenLP 2.0 song database.'))
|
||||
return
|
||||
self.import_source = 'sqlite:///%s' % self.import_source
|
||||
# Load the db file
|
||||
engine = create_engine(self.import_source)
|
||||
source_meta = MetaData()
|
||||
source_meta.reflect(engine)
|
||||
self.sourceSession = scoped_session(sessionmaker(bind=engine))
|
||||
self.source_session = scoped_session(sessionmaker(bind=engine))
|
||||
if 'media_files' in list(source_meta.tables.keys()):
|
||||
has_media_files = True
|
||||
else:
|
||||
@ -143,12 +137,11 @@ class OpenLPSongImport(SongImport):
|
||||
}
|
||||
if has_media_files:
|
||||
if isinstance(source_media_files_songs_table, Table):
|
||||
song_props['media_files'] = relation(OldMediaFile,
|
||||
backref='songs',
|
||||
song_props['media_files'] = relation(OldMediaFile, backref='songs',
|
||||
secondary=source_media_files_songs_table)
|
||||
else:
|
||||
song_props['media_files'] = relation(OldMediaFile,
|
||||
backref='songs',
|
||||
song_props['media_files'] = \
|
||||
relation(OldMediaFile, backref='songs',
|
||||
foreign_keys=[source_media_files_table.c.song_id],
|
||||
primaryjoin=source_songs_table.c.id == source_media_files_table.c.song_id)
|
||||
try:
|
||||
@ -168,7 +161,7 @@ class OpenLPSongImport(SongImport):
|
||||
except UnmappedClassError:
|
||||
mapper(OldTopic, source_topics_table)
|
||||
|
||||
source_songs = self.sourceSession.query(OldSong).all()
|
||||
source_songs = self.source_session.query(OldSong).all()
|
||||
if self.import_wizard:
|
||||
self.import_wizard.progress_bar.setMaximum(len(source_songs))
|
||||
for song in source_songs:
|
||||
@ -212,17 +205,17 @@ class OpenLPSongImport(SongImport):
|
||||
if has_media_files:
|
||||
if song.media_files:
|
||||
for media_file in song.media_files:
|
||||
existing_media_file = self.manager.get_object_filtered(MediaFile,
|
||||
MediaFile.file_name == media_file.file_name)
|
||||
existing_media_file = self.manager.get_object_filtered(
|
||||
MediaFile, MediaFile.file_name == media_file.file_name)
|
||||
if existing_media_file:
|
||||
new_song.media_files.append(existing_media_file)
|
||||
else:
|
||||
new_song.media_files.append(MediaFile.populate(file_name=media_file.file_name))
|
||||
clean_song(self.manager, new_song)
|
||||
self.manager.save_object(new_song)
|
||||
if progressDialog:
|
||||
progressDialog.setValue(progressDialog.value() + 1)
|
||||
progressDialog.setLabelText(WizardStrings.ImportingType % new_song.title)
|
||||
if progress_dialog:
|
||||
progress_dialog.setValue(progress_dialog.value() + 1)
|
||||
progress_dialog.setLabelText(WizardStrings.ImportingType % new_song.title)
|
||||
else:
|
||||
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % new_song.title)
|
||||
if self.stop_import_flag:
|
||||
|
@ -27,8 +27,8 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`openlyricsexport` module provides the functionality for exporting
|
||||
songs from the database to the OpenLyrics format.
|
||||
The :mod:`openlyricsexport` module provides the functionality for exporting songs from the database to the OpenLyrics
|
||||
format.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
@ -62,7 +62,7 @@ class OpenLyricsExport(object):
|
||||
Export the songs.
|
||||
"""
|
||||
log.debug('started OpenLyricsExport')
|
||||
openLyrics = OpenLyrics(self.manager)
|
||||
open_lyrics = OpenLyrics(self.manager)
|
||||
self.parent.progress_bar.setMaximum(len(self.songs))
|
||||
for song in self.songs:
|
||||
self.application.process_events()
|
||||
@ -70,7 +70,7 @@ class OpenLyricsExport(object):
|
||||
return False
|
||||
self.parent.increment_progress_bar(translate('SongsPlugin.OpenLyricsExport', 'Exporting "%s"...') %
|
||||
song.title)
|
||||
xml = openLyrics.song_to_xml(song)
|
||||
xml = open_lyrics.song_to_xml(song)
|
||||
tree = etree.ElementTree(etree.fromstring(xml.encode()))
|
||||
filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors]))
|
||||
filename = clean_filename(filename)
|
||||
@ -78,8 +78,8 @@ class OpenLyricsExport(object):
|
||||
filename = '%s.xml' % filename[0:250 - len(self.save_path)]
|
||||
# Pass a file object, because lxml does not cope with some special
|
||||
# characters in the path (see lp:757673 and lp:744337).
|
||||
tree.write(open(os.path.join(self.save_path, filename), 'wb'),
|
||||
encoding='utf-8', xml_declaration=True, pretty_print=True)
|
||||
tree.write(open(os.path.join(self.save_path, filename), 'wb'), encoding='utf-8', xml_declaration=True,
|
||||
pretty_print=True)
|
||||
return True
|
||||
|
||||
def _get_application(self):
|
||||
|
@ -54,7 +54,7 @@ class OpenLyricsImport(SongImport):
|
||||
"""
|
||||
log.debug('initialise OpenLyricsImport')
|
||||
SongImport.__init__(self, manager, **kwargs)
|
||||
self.openLyrics = OpenLyrics(self.manager)
|
||||
self.open_lyrics = OpenLyrics(self.manager)
|
||||
|
||||
def do_import(self):
|
||||
"""
|
||||
@ -71,11 +71,11 @@ class OpenLyricsImport(SongImport):
|
||||
# special characters in the path (see lp:757673 and lp:744337).
|
||||
parsed_file = etree.parse(open(file_path, 'r'), parser)
|
||||
xml = etree.tostring(parsed_file).decode()
|
||||
self.openLyrics.xml_to_song(xml)
|
||||
self.open_lyrics.xml_to_song(xml)
|
||||
except etree.XMLSyntaxError:
|
||||
log.exception('XML syntax error in file %s' % file_path)
|
||||
self.log_error(file_path, SongStrings.XMLSyntaxError)
|
||||
except OpenLyricsError as exception:
|
||||
log.exception('OpenLyricsException %d in file %s: %s'
|
||||
% (exception.type, file_path, exception.log_message))
|
||||
log.exception('OpenLyricsException %d in file %s: %s' %
|
||||
(exception.type, file_path, exception.log_message))
|
||||
self.log_error(file_path, exception.display_message)
|
||||
|
@ -115,10 +115,10 @@ class OpenSongImport(SongImport):
|
||||
if self.stop_import_flag:
|
||||
return
|
||||
song_file = open(filename)
|
||||
self.doImportFile(song_file)
|
||||
self.do_import_file(song_file)
|
||||
song_file.close()
|
||||
|
||||
def doImportFile(self, file):
|
||||
def do_import_file(self, file):
|
||||
"""
|
||||
Process the OpenSong file - pass in a file-like object, not a file path.
|
||||
"""
|
||||
@ -132,7 +132,7 @@ class OpenSongImport(SongImport):
|
||||
root = tree.getroot()
|
||||
if root.tag != 'song':
|
||||
self.log_error(file.name, str(
|
||||
translate('SongsPlugin.OpenSongImport', ('Invalid OpenSong song file. Missing song tag.'))))
|
||||
translate('SongsPlugin.OpenSongImport', 'Invalid OpenSong song file. Missing song tag.')))
|
||||
return
|
||||
fields = dir(root)
|
||||
decode = {
|
||||
@ -218,7 +218,7 @@ class OpenSongImport(SongImport):
|
||||
for (verse_tag, verse_num, inst) in our_verse_order:
|
||||
lines = '\n'.join(verses[verse_tag][verse_num][inst])
|
||||
length = 0
|
||||
while(length < len(verse_num) and verse_num[length].isnumeric()):
|
||||
while length < len(verse_num) and verse_num[length].isnumeric():
|
||||
length += 1
|
||||
verse_def = '%s%s' % (verse_tag, verse_num[:length])
|
||||
verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \
|
||||
@ -248,7 +248,7 @@ class OpenSongImport(SongImport):
|
||||
if verse_num in verses.get(verse_tag, {}):
|
||||
self.verse_order_list.append(verse_def)
|
||||
else:
|
||||
log.info('Got order %s but not in verse tags, dropping'
|
||||
'this item from presentation order', verse_def)
|
||||
log.info('Got order %s but not in verse tags, dropping this item from presentation order',
|
||||
verse_def)
|
||||
if not self.finish():
|
||||
self.log_error(file.name)
|
||||
|
@ -39,6 +39,7 @@ from openlp.plugins.songs.lib.songimport import SongImport
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PowerSongImport(SongImport):
|
||||
"""
|
||||
The :class:`PowerSongImport` class provides the ability to import song files
|
||||
@ -90,7 +91,7 @@ class PowerSongImport(SongImport):
|
||||
Receive either a list of files or a folder (unicode) to import.
|
||||
"""
|
||||
from .importer import SongFormat
|
||||
PS_string = SongFormat.get(SongFormat.PowerSong, 'name')
|
||||
ps_string = SongFormat.get(SongFormat.PowerSong, 'name')
|
||||
if isinstance(self.import_source, str):
|
||||
if os.path.isdir(self.import_source):
|
||||
dir = self.import_source
|
||||
@ -102,7 +103,7 @@ class PowerSongImport(SongImport):
|
||||
self.import_source = ''
|
||||
if not self.import_source or not isinstance(self.import_source, list):
|
||||
self.log_error(translate('SongsPlugin.PowerSongImport', 'No songs to import.'),
|
||||
translate('SongsPlugin.PowerSongImport', 'No %s files found.') % PS_string)
|
||||
translate('SongsPlugin.PowerSongImport', 'No %s files found.') % ps_string)
|
||||
return
|
||||
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
|
||||
for file in self.import_source:
|
||||
@ -113,15 +114,15 @@ class PowerSongImport(SongImport):
|
||||
with open(file, 'rb') as song_data:
|
||||
while True:
|
||||
try:
|
||||
label = self._readString(song_data)
|
||||
label = self._read_string(song_data)
|
||||
if not label:
|
||||
break
|
||||
field = self._readString(song_data)
|
||||
field = self._read_string(song_data)
|
||||
except ValueError:
|
||||
parse_error = True
|
||||
self.log_error(os.path.basename(file), str(
|
||||
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.')) %
|
||||
PS_string)
|
||||
ps_string)
|
||||
break
|
||||
else:
|
||||
if label == 'TITLE':
|
||||
@ -130,7 +131,7 @@ class PowerSongImport(SongImport):
|
||||
self.parse_author(field)
|
||||
elif label == 'COPYRIGHTLINE':
|
||||
found_copyright = True
|
||||
self._parseCopyrightCCLI(field)
|
||||
self._parse_copyright_cCCLI(field)
|
||||
elif label == 'PART':
|
||||
self.add_verse(field)
|
||||
if parse_error:
|
||||
@ -138,13 +139,13 @@ class PowerSongImport(SongImport):
|
||||
# Check that file had TITLE field
|
||||
if not self.title:
|
||||
self.log_error(os.path.basename(file), str(
|
||||
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % PS_string)
|
||||
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % ps_string)
|
||||
continue
|
||||
# Check that file had COPYRIGHTLINE label
|
||||
if not found_copyright:
|
||||
self.log_error(self.title, str(
|
||||
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) %
|
||||
PS_string)
|
||||
ps_string)
|
||||
continue
|
||||
# Check that file had at least one verse
|
||||
if not self.verses:
|
||||
@ -154,14 +155,14 @@ class PowerSongImport(SongImport):
|
||||
if not self.finish():
|
||||
self.log_error(self.title)
|
||||
|
||||
def _readString(self, file_object):
|
||||
def _read_string(self, file_object):
|
||||
"""
|
||||
Reads in next variable-length string.
|
||||
"""
|
||||
string_len = self._read7BitEncodedInteger(file_object)
|
||||
string_len = self._read_7_bit_encoded_integer(file_object)
|
||||
return str(file_object.read(string_len), 'utf-8', 'ignore')
|
||||
|
||||
def _read7BitEncodedInteger(self, file_object):
|
||||
def _read_7_bit_encoded_integer(self, file_object):
|
||||
"""
|
||||
Reads in a 32-bit integer in compressed 7-bit format.
|
||||
|
||||
@ -179,7 +180,7 @@ class PowerSongImport(SongImport):
|
||||
# Check for corrupted stream (since max 5 bytes per 32-bit integer)
|
||||
if i == 5:
|
||||
raise ValueError
|
||||
byte = self._readByte(file_object)
|
||||
byte = self._read_byte(file_object)
|
||||
# Strip high bit and shift left
|
||||
val += (byte & 0x7f) << shift
|
||||
shift += 7
|
||||
@ -189,7 +190,7 @@ class PowerSongImport(SongImport):
|
||||
i += 1
|
||||
return val
|
||||
|
||||
def _readByte(self, file_object):
|
||||
def _read_byte(self, file_object):
|
||||
"""
|
||||
Reads in next byte as an unsigned integer
|
||||
|
||||
@ -202,7 +203,7 @@ class PowerSongImport(SongImport):
|
||||
else:
|
||||
return ord(byte_str)
|
||||
|
||||
def _parseCopyrightCCLI(self, field):
|
||||
def _parse_copyright_cCCLI(self, field):
|
||||
"""
|
||||
Look for CCLI song number, and get copyright
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user