def _extract_verse_order(self, verse_order): order = [] order_names = str(verse_order).split() for item in order_names: if len(item) == 1: verse_index = VerseType.from_translated_tag(item, None) if verse_index is not None: order.append(VerseType.tags[verse_index] + '1') else: # it matches no verses anyway order.append('') else: verse_index = VerseType.from_translated_tag(item[0], None) if verse_index is None: # it matches no verses anyway order.append('') else: verse_tag = VerseType.tags[verse_index] verse_num = item[1:].lower() order.append(verse_tag + verse_num) return order
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: {service}, {item}, {remote}'.format(service=service_item, item=item, remote=self.remote_song)) item_id = self._get_id_of_item_to_generate(item, self.remote_song) service_item.add_capability(ItemCapabilities.CanEdit) service_item.add_capability(ItemCapabilities.CanPreview) service_item.add_capability(ItemCapabilities.CanLoop) service_item.add_capability(ItemCapabilities.OnLoadUpdate) service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.CanSoftBreak) song = self.plugin.manager.get_object(Song, item_id) service_item.theme = song.theme_name service_item.edit_id = item_id verse_list = SongXML().get_verses(song.lyrics) # no verse list or only 1 space (in error) verse_tags_translated = False if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None: verse_tags_translated = True if not song.verse_order.strip(): for verse in verse_list: # We cannot use from_loose_input() here, because database is supposed to contain English lowercase # singlechar tags. verse_tag = verse[0]['type'] verse_index = None if len(verse_tag) > 1: verse_index = VerseType.from_translated_string(verse_tag) if verse_index is None: verse_index = VerseType.from_string(verse_tag, None) if verse_index is None: verse_index = VerseType.from_tag(verse_tag) verse_tag = VerseType.translated_tags[verse_index].upper() verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) service_item.add_from_text(str(verse[1]), verse_def) else: # Loop through the verse list and expand the song accordingly. for order in song.verse_order.lower().split(): 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_tags_translated: verse_index = VerseType.from_translated_tag(verse[0]['type']) else: verse_index = VerseType.from_tag(verse[0]['type']) verse_tag = VerseType.translated_tags[verse_index] verse_def = '{tag}{text}'.format(tag=verse_tag, text=verse[0]['label']) service_item.add_from_text(verse[1], verse_def) 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.open_lyrics.song_to_xml(song) # Add the audio file to the service item. if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) service_item.background_audio = [m.file_name for m in song.media_files] return True
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) service_item.add_capability(ItemCapabilities.CanEdit) service_item.add_capability(ItemCapabilities.CanPreview) service_item.add_capability(ItemCapabilities.CanLoop) service_item.add_capability(ItemCapabilities.OnLoadUpdate) service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.CanSoftBreak) song = self.plugin.manager.get_object(Song, item_id) service_item.theme = song.theme_name service_item.edit_id = item_id verse_list = SongXML().get_verses(song.lyrics) # no verse list or only 1 space (in error) verse_tags_translated = False if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None: verse_tags_translated = True if not song.verse_order.strip(): for verse in verse_list: # We cannot use from_loose_input() here, because database is supposed to contain English lowercase # singlechar tags. verse_tag = verse[0]['type'] verse_index = None if len(verse_tag) > 1: verse_index = VerseType.from_translated_string(verse_tag) if verse_index is None: verse_index = VerseType.from_string(verse_tag, None) if verse_index is None: verse_index = VerseType.from_tag(verse_tag) verse_tag = VerseType.translated_tags[verse_index].upper() verse_def = '%s%s' % (verse_tag, verse[0]['label']) service_item.add_from_text(str(verse[1]), verse_def) else: # Loop through the verse list and expand the song accordingly. for order in song.verse_order.lower().split(): 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_tags_translated: verse_index = VerseType.from_translated_tag(verse[0]['type']) else: verse_index = VerseType.from_tag(verse[0]['type']) 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) 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.set_extra_data_dict(self.open_lyrics.song_to_line_dict(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) service_item.background_audio = [m.file_name for m in song.media_files] return True
def save_song(self, preview=False): """ Get all the data from the widgets on the form, and then save it to the database. The form has been validated and all reference items (Authors, Books and Topics) have been saved before this function is called. ``preview`` Should be ``True`` if the song is also previewed (boolean). """ # The Song() assignment. No database calls should be made while a # Song() is in a partially complete state. if not self.song: self.song = Song() self.song.title = self.title_edit.text() self.song.alternate_title = self.alternative_edit.text() self.song.copyright = self.copyright_edit.text() # Values will be set when cleaning the song. self.song.search_title = '' self.song.search_lyrics = '' self.song.verse_order = '' self.song.comments = self.comments_edit.toPlainText() ordertext = self.verse_order_edit.text() order = [] for item in ordertext.split(): verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])] verse_num = item[1:].lower() order.append('%s%s' % (verse_tag, verse_num)) self.song.verse_order = ' '.join(order) self.song.ccli_number = self.ccli_number_edit.text() self.song.song_number = self.song_book_number_edit.text() book_name = self.song_book_combo_box.currentText() if book_name: self.song.book = self.manager.get_object_filtered(Book, Book.name == book_name) else: self.song.book = None theme_name = self.theme_combo_box.currentText() if theme_name: self.song.theme_name = theme_name else: self.song.theme_name = None self._process_lyrics() self.song.authors = [] for row in range(self.authors_list_view.count()): item = self.authors_list_view.item(row) authorId = (item.data(QtCore.Qt.UserRole)) author = self.manager.get_object(Author, authorId) if author is not None: self.song.authors.append(author) self.song.topics = [] for row in range(self.topics_list_view.count()): item = self.topics_list_view.item(row) topicId = (item.data(QtCore.Qt.UserRole)) topic = self.manager.get_object(Topic, topicId) if topic is not None: self.song.topics.append(topic) # Save the song here because we need a valid id for the audio files. clean_song(self.manager, self.song) self.manager.save_object(self.song) audio_files = [a.file_name for a in self.song.media_files] log.debug(audio_files) save_path = os.path.join(AppLocation.get_section_data_path(self.media_item.plugin.name), 'audio', str(self.song.id)) check_directory_exists(save_path) self.song.media_files = [] files = [] for row in range(self.audio_list_widget.count()): item = self.audio_list_widget.item(row) filename = item.data(QtCore.Qt.UserRole) if not filename.startswith(save_path): oldfile, filename = filename, os.path.join(save_path, os.path.split(filename)[1]) shutil.copyfile(oldfile, filename) files.append(filename) media_file = MediaFile() media_file.file_name = filename media_file.type = 'audio' media_file.weight = row self.song.media_files.append(media_file) for audio in audio_files: if audio not in files: try: os.remove(audio) except: log.exception('Could not remove file: %s', audio) if not files: try: os.rmdir(save_path) except OSError: log.exception('Could not remove directory: %s', save_path) clean_song(self.manager, self.song) self.manager.save_object(self.song) self.media_item.auto_select_id = self.song.id
def load_song(self, song_id, preview=False): """ Loads a song. ``song_id`` The song id (int). ``preview`` Should be ``True`` if the song is also previewed (boolean). """ log.debug('Load Song') self.initialise() self.song_tab_widget.setCurrentIndex(0) self.load_authors() self.load_topics() self.load_books() self.load_media_files() self.song = self.manager.get_object(Song, song_id) self.title_edit.setText(self.song.title) self.alternative_edit.setText( self.song.alternate_title if self.song.alternate_title else '') if self.song.song_book_id != 0: book_name = self.manager.get_object(Book, self.song.song_book_id) find_and_set_in_combo_box(self.song_book_combo_box, str(book_name.name)) else: self.song_book_combo_box.setEditText('') self.song_book_combo_box.setCurrentIndex(0) if self.song.theme_name: find_and_set_in_combo_box(self.theme_combo_box, str(self.song.theme_name)) else: # Clear the theme combo box in case it was previously set (bug #1212801) self.theme_combo_box.setEditText('') self.theme_combo_box.setCurrentIndex(0) self.copyright_edit.setText(self.song.copyright if self.song.copyright else '') self.comments_edit.setPlainText(self.song.comments if self.song.comments else '') self.ccli_number_edit.setText(self.song.ccli_number if self.song.ccli_number else '') self.song_book_number_edit.setText(self.song.song_number if self.song.song_number else '') # lazy xml migration for now self.verse_list_widget.clear() self.verse_list_widget.setRowCount(0) verse_tags_translated = False if self.song.lyrics.startswith('<?xml version='): songXML = SongXML() verse_list = songXML.get_verses(self.song.lyrics) for count, verse in enumerate(verse_list): self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1) # This silently migrates from localized verse type markup. # If we trusted the database, this would be unnecessary. verse_tag = verse[0]['type'] index = None if len(verse_tag) > 1: index = VerseType.from_translated_string(verse_tag) if index is None: index = VerseType.from_string(verse_tag, None) else: verse_tags_translated = True if index is None: index = VerseType.from_tag(verse_tag) verse[0]['type'] = VerseType.tags[index] if verse[0]['label'] == '': verse[0]['label'] = '1' verse_def = '%s%s' % (verse[0]['type'], verse[0]['label']) item = QtGui.QTableWidgetItem(verse[1]) item.setData(QtCore.Qt.UserRole, verse_def) self.verse_list_widget.setItem(count, 0, item) else: verses = self.song.lyrics.split('\n\n') for count, verse in enumerate(verses): self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1) item = QtGui.QTableWidgetItem(verse) verse_def = '%s%s' % (VerseType.tags[VerseType.Verse], str(count + 1)) item.setData(QtCore.Qt.UserRole, verse_def) self.verse_list_widget.setItem(count, 0, item) if self.song.verse_order: # we translate verse order translated = [] for verse_def in self.song.verse_order.split(): verse_index = None if verse_tags_translated: verse_index = VerseType.from_translated_tag(verse_def[0], None) if verse_index is None: verse_index = VerseType.from_tag(verse_def[0]) verse_tag = VerseType.translated_tags[verse_index].upper() translated.append('%s%s' % (verse_tag, verse_def[1:])) self.verse_order_edit.setText(' '.join(translated)) else: self.verse_order_edit.setText('') self.tag_rows() # clear the results self.authors_list_view.clear() for author in self.song.authors: author_name = QtGui.QListWidgetItem(str(author.display_name)) author_name.setData(QtCore.Qt.UserRole, author.id) self.authors_list_view.addItem(author_name) # clear the results self.topics_list_view.clear() for topic in self.song.topics: topic_name = QtGui.QListWidgetItem(str(topic.name)) topic_name.setData(QtCore.Qt.UserRole, topic.id) self.topics_list_view.addItem(topic_name) self.audio_list_widget.clear() for media in self.song.media_files: media_file = QtGui.QListWidgetItem(os.path.split(media.file_name)[1]) media_file.setData(QtCore.Qt.UserRole, media.file_name) self.audio_list_widget.addItem(media_file) self.title_edit.setFocus() # Hide or show the preview button. self.preview_button.setVisible(preview) # Check if all verse tags are used. self.on_verse_order_text_changed(self.verse_order_edit.text())
def generateSlideData(self, service_item, item=None, xmlVersion=False, remote=False, context=ServiceItemContext.Service): log.debug(u'generateSlideData: %s, %s, %s' % (service_item, item, self.remoteSong)) item_id = self._getIdOfItemToGenerate(item, self.remoteSong) service_item.add_capability(ItemCapabilities.CanEdit) service_item.add_capability(ItemCapabilities.CanPreview) service_item.add_capability(ItemCapabilities.CanLoop) service_item.add_capability(ItemCapabilities.OnLoadUpdate) service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.CanSoftBreak) 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(u'<?xml version='): verse_list = SongXML().get_verses(song.lyrics) # no verse list or only 1 space (in error) verse_tags_translated = False if VerseType.from_translated_string(unicode(verse_list[0][0][u'type'])) is not None: verse_tags_translated = True if not song.verse_order.strip(): for verse in verse_list: # We cannot use from_loose_input() here, because database # is supposed to contain English lowercase singlechar tags. verse_tag = verse[0][u'type'] verse_index = None if len(verse_tag) > 1: verse_index = VerseType.from_translated_string(verse_tag) if verse_index is None: verse_index = VerseType.from_string(verse_tag, None) if verse_index is None: verse_index = VerseType.from_tag(verse_tag) verse_tag = VerseType.TranslatedTags[verse_index].upper() verse_def = u'%s%s' % (verse_tag, verse[0][u'label']) service_item.add_from_text(unicode(verse[1]), verse_def) else: # Loop through the verse list and expand the song accordingly. for order in song.verse_order.lower().split(): if not order: break for verse in verse_list: if verse[0][u'type'][0].lower() == order[0] and (verse[0][u'label'].lower() == order[1:] or \ not order[1:]): if verse_tags_translated: verse_index = VerseType.from_translated_tag(verse[0][u'type']) else: verse_index = VerseType.from_tag(verse[0][u'type']) verse_tag = VerseType.TranslatedTags[verse_index] verse_def = u'%s%s' % (verse_tag, verse[0][u'label']) service_item.add_from_text(verse[1], verse_def) else: verses = song.lyrics.split(u'\n\n') for slide in verses: service_item.add_from_text(unicode(slide)) service_item.title = song.title author_list = [unicode(author.display_name) for author in song.authors] service_item.raw_footer.append(song.title) service_item.raw_footer.append(create_separated_list(author_list)) service_item.raw_footer.append(song.copyright) if Settings().value(u'general/ccli number'): service_item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') + Settings().value(u'general/ccli number')) service_item.audit = [ song.title, author_list, song.copyright, unicode(song.ccli_number) ] service_item.data_string = {u'title': song.search_title, u'authors': u', '.join(author_list)} service_item.xml_version = self.openLyrics.song_to_xml(song) # Add the audio file to the service item. if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) service_item.background_audio = [m.file_name for m in song.media_files] return True
def generate_slide_data(self, service_item, *, item=None, context=ServiceItemContext.Service, **kwargs): """ 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 context: Why is it being generated :param kwargs: Consume other unused args specified by the base implementation, but not use by this one. """ log.debug('generate_slide_data: {service}, {item}, {remote}'.format( service=service_item, item=item, remote=self.remote_song)) item_id = self._get_id_of_item_to_generate(item, self.remote_song) service_item.add_capability(ItemCapabilities.CanEdit) service_item.add_capability(ItemCapabilities.CanPreview) service_item.add_capability(ItemCapabilities.CanLoop) service_item.add_capability(ItemCapabilities.OnLoadUpdate) service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.CanSoftBreak) service_item.add_capability(ItemCapabilities.HasMetaData) song = self.plugin.manager.get_object(Song, item_id) service_item.theme = song.theme_name service_item.edit_id = item_id verse_list = SongXML().get_verses(song.lyrics) if self.settings.value( 'songs/add songbook slide') and song.songbook_entries: first_slide = '\n' for songbook_entry in song.songbook_entries: first_slide += '{book} #{num}'.format( book=songbook_entry.songbook.name, num=songbook_entry.entry) if songbook_entry.songbook.publisher: first_slide += ' ({pub})'.format( pub=songbook_entry.songbook.publisher) first_slide += '\n\n' service_item.add_from_text(first_slide, 'O1') # no verse list or only 1 space (in error) verse_tags_translated = False if VerseType.from_translated_string(str( verse_list[0][0]['type'])) is not None: verse_tags_translated = True if not song.verse_order.strip(): for verse in verse_list: # We cannot use from_loose_input() here, because database is supposed to contain English lowercase # single char tags. verse_tag = verse[0]['type'] verse_index = None if len(verse_tag) > 1: verse_index = VerseType.from_translated_string(verse_tag) if verse_index is None: verse_index = VerseType.from_string(verse_tag, None) if verse_index is None: verse_index = VerseType.from_tag(verse_tag) verse_tag = VerseType.translated_tags[verse_index].upper() verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) force_verse = verse[1].split('[--}{--]\n') for split_verse in force_verse: service_item.add_from_text(split_verse, verse_def) else: # Loop through the verse list and expand the song accordingly. for order in song.verse_order.lower().split(): 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_tags_translated: verse_index = VerseType.from_translated_tag( verse[0]['type']) else: verse_index = VerseType.from_tag(verse[0]['type']) verse_tag = VerseType.translated_tags[verse_index] verse_def = '{tag}{label}'.format( tag=verse_tag, label=verse[0]['label']) force_verse = verse[1].split('[--}{--]\n') for split_verse in force_verse: service_item.add_from_text(split_verse, verse_def) 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.open_lyrics.song_to_xml(song) # Add the audio file to the service item. if song.media_files: if State().check_preconditions('media'): service_item.add_capability( ItemCapabilities.HasBackgroundAudio) total_length = 0 for m in song.media_files: total_length += self.media_controller.media_length( m.file_path) service_item.background_audio = [ m.file_path for m in song.media_files ] service_item.set_media_length(total_length) service_item.metadata.append( '<em>{label}:</em> {media}'.format( label=translate('SongsPlugin.MediaItem', 'Media'), media=service_item.background_audio)) return True