~gtalent/openlp/openlp

« back to all changes in this revision

Viewing changes to openlp/plugins/songs/lib/importers/easyworship.py

  • Committer: Gary Talent
  • Date: 2016-09-07 05:15:37 UTC
  • Revision ID: gtalent2@gmail.com-20160907051537-rc808cwftw65esaa
Add support for importing EasyWorship6 databases

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
import re
29
29
import zlib
30
30
import logging
 
31
import sqlite3
31
32
 
32
33
from openlp.core.lib import translate
33
34
from openlp.plugins.songs.lib import VerseType
77
78
        """
78
79
        if self.import_source.lower().endswith('ews'):
79
80
            self.import_ews()
80
 
        else:
 
81
        elif self.import_source.endswith('DB'):
81
82
            self.import_db()
 
83
        else:
 
84
            self.import_sqlite_db()
82
85
 
83
86
    def import_ews(self):
84
87
        """
125
128
        else:
126
129
            log.debug('Given ews file is of unknown version.')
127
130
            return
128
 
        entry_count = self.get_i32(file_pos)
129
 
        entry_length = self.get_i16(file_pos + 4)
 
131
        entry_count = self.ews_get_i32(file_pos)
 
132
        entry_length = self.ews_get_i16(file_pos + 4)
130
133
        file_pos += 6
131
134
        self.import_wizard.progress_bar.setMaximum(entry_count)
132
135
        # Loop over songs
144
147
            #                                                       0x08 = Audio, 0x09 = Web
145
148
            #   1410  Song number            cstring          10
146
149
            self.set_defaults()
147
 
            self.title = self.get_string(file_pos + 0, 50)
148
 
            authors = self.get_string(file_pos + 307, 50)
149
 
            copyright = self.get_string(file_pos + 358, 100)
150
 
            admin = self.get_string(file_pos + 459, 50)
151
 
            cont_ptr = self.get_i32(file_pos + 800)
152
 
            cont_type = self.get_i32(file_pos + 820)
153
 
            self.ccli_number = self.get_string(file_pos + 1410, 10)
 
150
            self.title = self.ews_get_string(file_pos + 0, 50)
 
151
            authors = self.ews_get_string(file_pos + 307, 50)
 
152
            copyright = self.ews_get_string(file_pos + 358, 100)
 
153
            admin = self.ews_get_string(file_pos + 459, 50)
 
154
            cont_ptr = self.ews_get_i32(file_pos + 800)
 
155
            cont_type = self.ews_get_i32(file_pos + 820)
 
156
            self.ccli_number = self.ews_get_string(file_pos + 1410, 10)
154
157
            # Only handle content type 1 (songs)
155
158
            if cont_type != 1:
156
159
                file_pos += entry_length
164
167
            #         Checksum           int32be           4    Alder-32 checksum.
165
168
            #         (unknown)                            4    0x51 0x4b 0x03 0x04
166
169
            #         Content length     int32le           4    Length of content after decompression
167
 
            content_length = self.get_i32(cont_ptr)
168
 
            deflated_content = self.get_bytes(cont_ptr + 4, content_length - 10)
169
 
            deflated_length = self.get_i32(cont_ptr + 4 + content_length - 6)
 
170
            content_length = self.ews_get_i32(cont_ptr)
 
171
            deflated_content = self.ews_get_bytes(cont_ptr + 4, content_length - 10)
 
172
            deflated_length = self.ews_get_i32(cont_ptr + 4 + content_length - 6)
170
173
            inflated_content = zlib.decompress(deflated_content, 15, deflated_length)
171
174
            if copyright:
172
175
                self.copyright = copyright
196
199
        Import the songs from the database
197
200
        """
198
201
        # Open the DB and MB files if they exist
199
 
        import_source_mb = self.import_source.replace('.DB', '.MB').replace('.db', '.mb')
 
202
        import_source_mb = self.import_source.replace('.DB', '.MB')
200
203
        if not os.path.isfile(self.import_source):
201
204
            self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
202
205
                                                         'This file does not exist.'))
260
263
        for i, field_name in enumerate(field_names):
261
264
            field_type, field_size = struct.unpack_from('BB', field_info, i * 2)
262
265
            field_descriptions.append(FieldDescEntry(field_name, field_type, field_size))
263
 
        self.set_record_struct(field_descriptions)
 
266
        self.db_set_record_struct(field_descriptions)
264
267
        # Pick out the field description indexes we will need
265
268
        try:
266
269
            success = True
267
 
            fi_title = self.find_field(b'Title')
268
 
            fi_author = self.find_field(b'Author')
269
 
            fi_copy = self.find_field(b'Copyright')
270
 
            fi_admin = self.find_field(b'Administrator')
271
 
            fi_words = self.find_field(b'Words')
272
 
            fi_ccli = self.find_field(b'Song Number')
 
270
            fi_title = self.db_find_field(b'Title')
 
271
            fi_author = self.db_find_field(b'Author')
 
272
            fi_copy = self.db_find_field(b'Copyright')
 
273
            fi_admin = self.db_find_field(b'Administrator')
 
274
            fi_words = self.db_find_field(b'Words')
 
275
            fi_ccli = self.db_find_field(b'Song Number')
273
276
        except IndexError:
274
277
            # This is the wrong table
275
278
            success = False
297
300
                    raw_record = db_file.read(record_size)
298
301
                    self.fields = self.record_structure.unpack(raw_record)
299
302
                    self.set_defaults()
300
 
                    self.title = self.get_field(fi_title).decode(self.encoding)
 
303
                    self.title = self.db_get_field(fi_title).decode(self.encoding)
301
304
                    # Get remaining fields.
302
 
                    copy = self.get_field(fi_copy)
303
 
                    admin = self.get_field(fi_admin)
304
 
                    ccli = self.get_field(fi_ccli)
305
 
                    authors = self.get_field(fi_author)
306
 
                    words = self.get_field(fi_words)
 
305
                    copy = self.db_get_field(fi_copy)
 
306
                    admin = self.db_get_field(fi_admin)
 
307
                    ccli = self.db_get_field(fi_ccli)
 
308
                    authors = self.db_get_field(fi_author)
 
309
                    words = self.db_get_field(fi_words)
307
310
                    if copy:
308
311
                        self.copyright = copy.decode(self.encoding)
309
312
                    if admin:
337
340
        db_file.close()
338
341
        self.memo_file.close()
339
342
 
 
343
    def import_sqlite_db(self):
 
344
        # get database handles
 
345
        songs_conn = sqlite3.connect(self.import_source + "/Songs.db")
 
346
        words_conn = sqlite3.connect(self.import_source + "/SongWords.db")
 
347
        if songs_conn is None or words_conn is None:
 
348
            self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
 
349
                                                         'This is not a valid Easy Worship 6 database.'))
 
350
            songs_conn.close()
 
351
            words_conn.close()
 
352
            return
 
353
        songs_db = songs_conn.cursor()
 
354
        words_db = words_conn.cursor()
 
355
        if songs_conn is None or words_conn is None:
 
356
            self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
 
357
                                                         'This is not a valid Easy Worship 6 database.'))
 
358
            songs_conn.close()
 
359
            words_conn.close()
 
360
            return
 
361
 
 
362
        # Take a stab at how text is encoded
 
363
        self.encoding = 'cp1252'
 
364
        self.encoding = retrieve_windows_encoding(self.encoding)
 
365
        if not self.encoding:
 
366
            log.debug('No encoding set.')
 
367
            return
 
368
 
 
369
        # import songs
 
370
        songs = songs_db.execute('SELECT rowid,title,author,copyright,vendor_id FROM song;')
 
371
        for song in songs:
 
372
            song_id = song[0]
 
373
            # keep extra copy of title for error message because error check clears it
 
374
            self.title = title = song[1]
 
375
            self.author      = song[2]
 
376
            self.copyright   = song[3]
 
377
            self.ccli_number = song[4]
 
378
            words = words_db.execute('SELECT words FROM word WHERE song_id = ?;', (song_id,))
 
379
            self.set_song_import_object(self.author, words.fetchone()[0].encode())
 
380
            if not self.finish():
 
381
                self.log_error(self.import_source,
 
382
                               translate('SongsPlugin.EasyWorshipSongImport',
 
383
                                         '"{title}" could not be imported. {entry}').
 
384
                                         format(title=title, entry=self.entry_error_log))
 
385
 
 
386
        # close database handles
 
387
        songs_conn.close()
 
388
        words_conn.close()
 
389
        return
 
390
 
340
391
    def set_song_import_object(self, authors, words):
341
392
        """
342
393
        Set the SongImport object members.
409
460
            self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
410
461
                                           '\n[above are Song Tags with notes imported from EasyWorship]'))
411
462
 
412
 
    def find_field(self, field_name):
 
463
    def db_find_field(self, field_name):
413
464
        """
414
465
        Find a field in the descriptions
415
466
 
417
468
        """
418
469
        return [i for i, x in enumerate(self.field_descriptions) if x.name == field_name][0]
419
470
 
420
 
    def set_record_struct(self, field_descriptions):
 
471
    def db_set_record_struct(self, field_descriptions):
421
472
        """
422
473
        Save the record structure
423
474
 
445
496
        self.record_structure = struct.Struct(''.join(fsl))
446
497
        self.field_descriptions = field_descriptions
447
498
 
448
 
    def get_field(self, field_desc_index):
 
499
    def db_get_field(self, field_desc_index):
449
500
        """
450
501
        Extract the field
451
502
 
489
540
        else:
490
541
            return 0
491
542
 
492
 
    def get_bytes(self, pos, length):
 
543
    def ews_get_bytes(self, pos, length):
493
544
        """
494
545
        Get bytes from ews_file
495
546
 
500
551
        self.ews_file.seek(pos)
501
552
        return self.ews_file.read(length)
502
553
 
503
 
    def get_string(self, pos, length):
 
554
    def ews_get_string(self, pos, length):
504
555
        """
505
556
        Get string from ews_file
506
557
 
508
559
        :param length: Characters to read
509
560
        :return: String read
510
561
        """
511
 
        bytes = self.get_bytes(pos, length)
 
562
        bytes = self.ews_get_bytes(pos, length)
512
563
        mask = '<' + str(length) + 's'
513
564
        byte_str, = struct.unpack(mask, bytes)
514
565
        return byte_str.decode(self.encoding).replace('\0', '').strip()
515
566
 
516
 
    def get_i16(self, pos):
 
567
    def ews_get_i16(self, pos):
517
568
        """
518
569
        Get short int from ews_file
519
570
 
521
572
        :return: Short integer read
522
573
        """
523
574
 
524
 
        bytes = self.get_bytes(pos, 2)
 
575
        bytes = self.ews_get_bytes(pos, 2)
525
576
        mask = '<h'
526
577
        number, = struct.unpack(mask, bytes)
527
578
        return number
528
579
 
529
 
    def get_i32(self, pos):
 
580
    def ews_get_i32(self, pos):
530
581
        """
531
582
        Get long int from ews_file
532
583
 
533
584
        :param pos: Position to read from
534
585
        :return: Long integer read
535
586
        """
536
 
        bytes = self.get_bytes(pos, 4)
 
587
        bytes = self.ews_get_bytes(pos, 4)
537
588
        mask = '<i'
538
589
        number, = struct.unpack(mask, bytes)
539
590
        return number