Add ewsx song importer

This commit is contained in:
Tomas Groth 2024-04-09 15:19:58 +00:00
parent 39833c770d
commit fa05ee4b2d
4 changed files with 137 additions and 22 deletions

View File

@ -166,28 +166,29 @@ class SongFormat(object):
EasyWorshipDB = 7 EasyWorshipDB = 7
EasyWorshipSqliteDB = 8 EasyWorshipSqliteDB = 8
EasyWorshipService = 9 EasyWorshipService = 9
FoilPresenter = 10 EasyWorshipServiceSqliteDB = 10
LiveWorship = 11 FoilPresenter = 11
Lyrix = 12 LiveWorship = 12
MediaShout = 13 Lyrix = 13
OpenSong = 14 MediaShout = 14
OPSPro = 15 OpenSong = 15
PowerPraise = 16 OPSPro = 16
PowerSong = 17 PowerPraise = 17
PresentationManager = 18 PowerSong = 18
ProPresenter = 19 PresentationManager = 19
SingingTheFaith = 20 ProPresenter = 20
SongBeamer = 21 SingingTheFaith = 21
SongPro = 22 SongBeamer = 22
SongShowPlus = 23 SongPro = 23
SongsOfFellowship = 24 SongShowPlus = 24
SundayPlus = 25 SongsOfFellowship = 25
VideoPsalm = 26 SundayPlus = 26
WordsOfWorship = 27 VideoPsalm = 27
WorshipAssistant = 28 WordsOfWorship = 28
WorshipCenterPro = 29 WorshipAssistant = 29
ZionWorx = 30 WorshipCenterPro = 30
Datasoul = 31 ZionWorx = 31
Datasoul = 32
# Set optional attribute defaults # Set optional attribute defaults
__defaults__ = { __defaults__ = {
@ -278,6 +279,14 @@ class SongFormat(object):
'filter': '{text} (*.ews)'.format(text=translate('SongsPlugin.ImportWizardForm', 'filter': '{text} (*.ews)'.format(text=translate('SongsPlugin.ImportWizardForm',
'EasyWorship 2007/2009 Service File')) 'EasyWorship 2007/2009 Service File'))
}, },
EasyWorshipServiceSqliteDB: {
'class': EasyWorshipSongImport,
'name': 'EasyWorship 6/7 Service File',
'prefix': 'ew',
'selectMode': SongFormatSelect.SingleFile,
'filter': '{text} (*.ewsx)'.format(text=translate('SongsPlugin.ImportWizardForm',
'EasyWorship 6/7 Service File'))
},
FoilPresenter: { FoilPresenter: {
'class': FoilPresenterImport, 'class': FoilPresenterImport,
'name': 'Foilpresenter', 'name': 'Foilpresenter',
@ -487,6 +496,7 @@ class SongFormat(object):
SongFormat.EasyWorshipDB, SongFormat.EasyWorshipDB,
SongFormat.EasyWorshipSqliteDB, SongFormat.EasyWorshipSqliteDB,
SongFormat.EasyWorshipService, SongFormat.EasyWorshipService,
SongFormat.EasyWorshipServiceSqliteDB,
SongFormat.FoilPresenter, SongFormat.FoilPresenter,
SongFormat.LiveWorship, SongFormat.LiveWorship,
SongFormat.Lyrix, SongFormat.Lyrix,

View File

@ -28,6 +28,8 @@ import sqlite3
import struct import struct
import zlib import zlib
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile
from zipfile import ZipFile
from openlp.core.common.i18n import translate from openlp.core.common.i18n import translate
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding, strip_rtf from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding, strip_rtf
@ -83,6 +85,8 @@ class EasyWorshipSongImport(SongImport):
self.import_ews() self.import_ews()
elif ext == '.db': elif ext == '.db':
self.import_db() self.import_db()
elif ext == '.ewsx':
self.import_ewsx()
else: else:
self.import_sqlite_db() self.import_sqlite_db()
except Exception: except Exception:
@ -346,6 +350,65 @@ class EasyWorshipSongImport(SongImport):
db_file.close() db_file.close()
self.memo_file.close() self.memo_file.close()
def import_ewsx(self):
"""
Imports songs from an EasyWorship 6/7 service file, which is just a zip file with an Sqlite DB with text
resources. Non-text recources is also in the zip file, but is ignored.
"""
invalid_ewsx_msg = translate('SongsPlugin.EasyWorshipSongImport',
'This is not a valid Easy Worship 6/7 service file.')
# Open ewsx file if it exists
if not self.import_source.is_file():
log.debug('Given ewsx file does not exists.')
return
tmp_db_file = NamedTemporaryFile(delete=False)
with ZipFile(self.import_source, 'r') as eswx_file:
db_zfile = eswx_file.open('main.db')
# eswx has bad CRC for the database for some reason (custom CRC?), so skip the CRC
db_zfile._expected_crc = None
db_data = db_zfile.read()
tmp_db_file.write(db_data)
tmp_db_file.close()
ewsx_conn = sqlite3.connect(tmp_db_file.file.name)
if ewsx_conn is None:
self.log_error(self.import_source, invalid_ewsx_msg)
return
ewsx_db = ewsx_conn.cursor()
# Take a stab at how text is encoded
self.encoding = 'cp1252'
self.encoding = retrieve_windows_encoding(self.encoding)
if not self.encoding:
log.debug('No encoding set.')
return
# get list of songs in service file, presentation_type=6 means songs
songs_exec = ewsx_db.execute('SELECT rowid, title, author, copyright, reference_number '
'FROM presentation WHERE presentation_type=6;')
songs = songs_exec.fetchall()
for song in songs:
self.title = title = song[1]
self.author = song[2]
self.copyright = song[3]
self.ccli_number = song[4]
# get slides for the song, element_type=6 means songs, element_style_type=4 means song text
slides = ewsx_db.execute('SELECT rt.rtf '
'FROM element as e '
'JOIN slide as s ON e.slide_id = s.rowid '
'JOIN resource_text as rt ON rt.resource_id = e.foreground_resource_id '
'WHERE e.element_type=6 AND e.element_style_type=4 AND s.presentation_id = ? '
'ORDER BY s.order_index;', (song[0],))
for slide in slides:
if slide:
self.set_song_import_object(self.author, slide[0].encode())
# save song
if not self.finish():
self.log_error(self.import_source,
translate('SongsPlugin.EasyWorshipSongImport',
'"{title}" could not be imported. {entry}').
format(title=title, entry=self.entry_error_log))
# close database handles
ewsx_conn.close()
Path(tmp_db_file.file.name).unlink()
def import_sqlite_db(self): def import_sqlite_db(self):
""" """
Import the songs from an EasyWorship 6 SQLite database Import the songs from an EasyWorship 6 SQLite database

View File

@ -498,6 +498,48 @@ def test_ews_file_import(mocked_retrieve_windows_encoding: MagicMock, MockSongIm
mocked_finish.assert_called_with() mocked_finish.assert_called_with()
@patch('openlp.plugins.songs.lib.importers.easyworship.SongImport')
@patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding')
def test_ewsx_file_import(mocked_retrieve_windows_encoding: MagicMock, MockSongImport: MagicMock,
registry: Registry, settings: Settings):
"""
Test the actual import of song from ewsx file and check that the imported data is correct.
"""
# GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard",
# and mocked out "author", "add_copyright", "add_verse", "finish" methods.
mocked_retrieve_windows_encoding.return_value = 'cp1252'
mocked_manager = MagicMock()
mocked_import_wizard = MagicMock()
mocked_add_author = MagicMock()
mocked_add_verse = MagicMock()
mocked_finish = MagicMock()
mocked_title = MagicMock()
mocked_finish.return_value = True
importer = EasyWorshipSongImportLogger(mocked_manager)
importer.import_wizard = mocked_import_wizard
importer.stop_import_flag = False
importer.add_author = mocked_add_author
importer.add_verse = mocked_add_verse
importer.title = mocked_title
importer.finish = mocked_finish
importer.topics = []
# WHEN: Importing ews file
importer.import_source = str(TEST_PATH / 'test1.ewsx')
import_result = importer.do_import()
# THEN: do_import should return none, the song data should be as expected, and finish should have been
# called.
title = EWS_SONG_TEST_DATA['title']
assert import_result is None, 'do_import should return None when it has completed'
assert title in importer._title_assignment_list, 'title for should be "%s"' % title
mocked_add_author.assert_any_call(EWS_SONG_TEST_DATA['authors'][0])
for verse_text, verse_tag in EWS_SONG_TEST_DATA['verses']:
mocked_add_verse.assert_any_call(verse_text, verse_tag)
mocked_finish.assert_called_with()
@patch('openlp.plugins.songs.lib.importers.easyworship.SongImport') @patch('openlp.plugins.songs.lib.importers.easyworship.SongImport')
def test_import_rtf_unescaped_unicode(MockSongImport: MagicMock, registry: Registry, settings: Settings): def test_import_rtf_unescaped_unicode(MockSongImport: MagicMock, registry: Registry, settings: Settings):
""" """

Binary file not shown.