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

View File

@ -28,6 +28,8 @@ import sqlite3
import struct
import zlib
from pathlib import Path
from tempfile import NamedTemporaryFile
from zipfile import ZipFile
from openlp.core.common.i18n import translate
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding, strip_rtf
@ -83,6 +85,8 @@ class EasyWorshipSongImport(SongImport):
self.import_ews()
elif ext == '.db':
self.import_db()
elif ext == '.ewsx':
self.import_ewsx()
else:
self.import_sqlite_db()
except Exception:
@ -346,6 +350,65 @@ class EasyWorshipSongImport(SongImport):
db_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):
"""
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()
@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')
def test_import_rtf_unescaped_unicode(MockSongImport: MagicMock, registry: Registry, settings: Settings):
"""

Binary file not shown.