Clean search lyrics for formatting tags. Fixes bug #1655988.

Fix an issue with easyslide import not handling verse order correctly. Fixes bug #1655985.
Improve the songbeamer encoding detection. Fixes bug #1530597.
Handle a few videopsalm quirks. Fixes bug #1652851.

Fixes: https://launchpad.net/bugs/1655988, https://launchpad.net/bugs/1655985, https://launchpad.net/bugs/1530597, https://launchpad.net/bugs/1652851
This commit is contained in:
Tomas Groth 2017-01-22 18:04:32 +01:00
parent 93b10bb6e7
commit dc5de9a54d
9 changed files with 128 additions and 26 deletions

View File

@ -30,7 +30,7 @@ import re
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from openlp.core.common import AppLocation from openlp.core.common import AppLocation
from openlp.core.lib import translate from openlp.core.lib import translate, clean_tags
from openlp.core.utils import CONTROL_CHARS from openlp.core.utils import CONTROL_CHARS
from openlp.plugins.songs.lib.db import Author, MediaFile, Song, Topic from openlp.plugins.songs.lib.db import Author, MediaFile, Song, Topic
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
@ -381,7 +381,7 @@ def clean_song(manager, song):
if isinstance(song.lyrics, bytes): if isinstance(song.lyrics, bytes):
song.lyrics = str(song.lyrics, encoding='utf8') song.lyrics = str(song.lyrics, encoding='utf8')
verses = SongXML().get_verses(song.lyrics) verses = SongXML().get_verses(song.lyrics)
song.search_lyrics = ' '.join([clean_string(verse[1]) for verse in verses]) song.search_lyrics = ' '.join([clean_string(clean_tags(verse[1])) for verse in verses])
# The song does not have any author, add one. # The song does not have any author, add one.
if not song.authors_songs: if not song.authors_songs:
name = SongStrings.AuthorUnknown name = SongStrings.AuthorUnknown

View File

@ -179,7 +179,7 @@ class EasySlidesImport(SongImport):
reg = default_region reg = default_region
verses[reg] = {} verses[reg] = {}
# instance differentiates occurrences of same verse tag # instance differentiates occurrences of same verse tag
vt = 'V' vt = 'v'
vn = '1' vn = '1'
inst = 1 inst = 1
for line in lines: for line in lines:
@ -192,14 +192,14 @@ class EasySlidesImport(SongImport):
inst += 1 inst += 1
else: else:
# separators are not used, so empty line starts a new verse # separators are not used, so empty line starts a new verse
vt = 'V' vt = 'v'
vn = len(verses[reg].get(vt, {})) + 1 vn = len(verses[reg].get(vt, {})) + 1
inst = 1 inst = 1
elif line[0:7] == '[region': elif line[0:7] == '[region':
reg = self._extract_region(line) reg = self._extract_region(line)
verses.setdefault(reg, {}) verses.setdefault(reg, {})
if not regions_in_verses: if not regions_in_verses:
vt = 'V' vt = 'v'
vn = '1' vn = '1'
inst = 1 inst = 1
elif line[0] == '[': elif line[0] == '[':
@ -212,7 +212,7 @@ class EasySlidesImport(SongImport):
if match: if match:
marker = match.group(1).strip() marker = match.group(1).strip()
vn = match.group(2) vn = match.group(2)
vt = MarkTypes.get(marker, 'O') if marker else 'V' vt = MarkTypes.get(marker, 'o') if marker else 'v'
if regions_in_verses: if regions_in_verses:
region = default_region region = default_region
inst = 1 inst = 1
@ -237,13 +237,13 @@ class EasySlidesImport(SongImport):
lines = '\n'.join(verses[reg][vt][vn][inst]) lines = '\n'.join(verses[reg][vt][vn][inst])
self.add_verse(lines, versetag) self.add_verse(lines, versetag)
SeqTypes = { SeqTypes = {
'p': 'P1', 'p': 'p1',
'q': 'P2', 'q': 'p2',
'c': 'C1', 'c': 'c1',
't': 'C2', 't': 'c2',
'b': 'B1', 'b': 'b1',
'w': 'B2', 'w': 'b2',
'e': 'E1'} 'e': 'e1'}
# Make use of Sequence data, determining the order of verses # Make use of Sequence data, determining the order of verses
try: try:
order = str(song.Sequence).strip().split(',') order = str(song.Sequence).strip().split(',')
@ -251,7 +251,7 @@ class EasySlidesImport(SongImport):
if not tag: if not tag:
continue continue
elif tag[0].isdigit(): elif tag[0].isdigit():
tag = 'V' + tag tag = 'v' + tag
elif tag.lower() in SeqTypes: elif tag.lower() in SeqTypes:
tag = SeqTypes[tag.lower()] tag = SeqTypes[tag.lower()]
else: else:

View File

@ -115,11 +115,15 @@ class SongBeamerImport(SongImport):
if os.path.isfile(import_file): if os.path.isfile(import_file):
# First open in binary mode to detect the encoding # First open in binary mode to detect the encoding
detect_file = open(import_file, 'rb') detect_file = open(import_file, 'rb')
details = chardet.detect(detect_file.read()) self.input_file_encoding = chardet.detect(detect_file.read())['encoding']
detect_file.close() detect_file.close()
infile = codecs.open(import_file, 'r', details['encoding']) # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.
# So if it doesn't start with 'u' we default to cp1252. See:
# https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
if self.input_file_encoding.lower().startswith('u'):
self.input_file_encoding = 'cp1252'
infile = open(import_file, 'rt', encoding=self.input_file_encoding)
song_data = infile.readlines() song_data = infile.readlines()
infile.close()
else: else:
continue continue
self.title = file_name.split('.sng')[0] self.title = file_name.split('.sng')[0]

View File

@ -65,8 +65,8 @@ class VideoPsalmImport(SongImport):
if c == '\n': if c == '\n':
if inside_quotes: if inside_quotes:
processed_content += '\\n' processed_content += '\\n'
# Put keys in quotes # Put keys in quotes. The '-' is for handling nagative numbers
elif c.isalnum() and not inside_quotes: elif (c.isalnum() or c == '-') and not inside_quotes:
processed_content += '"' + c processed_content += '"' + c
c = next(file_content_it) c = next(file_content_it)
while c.isalnum(): while c.isalnum():
@ -121,6 +121,8 @@ class VideoPsalmImport(SongImport):
if 'Memo3' in song: if 'Memo3' in song:
self.add_comment(song['Memo3']) self.add_comment(song['Memo3'])
for verse in song['Verses']: for verse in song['Verses']:
if 'Text' not in verse:
continue
self.add_verse(verse['Text'], 'v') self.add_verse(verse['Text'], 'v')
if not self.finish(): if not self.finish():
self.log_error('Could not import %s' % self.title) self.log_error('Could not import %s' % self.title)

View File

@ -43,3 +43,5 @@ class TestEasySlidesFileImport(SongImportTestHelper):
""" """
self.file_import(os.path.join(TEST_PATH, 'amazing-grace.xml'), self.file_import(os.path.join(TEST_PATH, 'amazing-grace.xml'),
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
self.file_import(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.xml'),
self.load_external_result_data(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.json')))

View File

@ -6,27 +6,27 @@
"verses": [ "verses": [
[ [
"Amazing grace! How sweet the sound\nThat saved a wretch like me;\nI once was lost, but now am found,\nWas blind, but now I see.", "Amazing grace! How sweet the sound\nThat saved a wretch like me;\nI once was lost, but now am found,\nWas blind, but now I see.",
"V1" "v1"
], ],
[ [
"'Twas grace that taught my heart to fear,\nAnd grace my fears relieved;\nHow precious did that grace appear,\nThe hour I first believed!", "'Twas grace that taught my heart to fear,\nAnd grace my fears relieved;\nHow precious did that grace appear,\nThe hour I first believed!",
"V2" "v2"
], ],
[ [
"Through many dangers, toils and snares\nI have already come;\n'Tis grace that brought me safe thus far,\nAnd grace will lead me home.", "Through many dangers, toils and snares\nI have already come;\n'Tis grace that brought me safe thus far,\nAnd grace will lead me home.",
"V3" "v3"
], ],
[ [
"The Lord has promised good to me,\nHis word my hope secures;\nHe will my shield and portion be\nAs long as life endures.", "The Lord has promised good to me,\nHis word my hope secures;\nHe will my shield and portion be\nAs long as life endures.",
"V4" "v4"
], ],
[ [
"Yes, when this heart and flesh shall fail,\nAnd mortal life shall cease,\nI shall possess within the veil\nA life of joy and peace.", "Yes, when this heart and flesh shall fail,\nAnd mortal life shall cease,\nI shall possess within the veil\nA life of joy and peace.",
"V5" "v5"
], ],
[ [
"When we've been there a thousand years,\nBright shining as the sun,\nWe've no less days to sing God's praise\nThan when we first begun.", "When we've been there a thousand years,\nBright shining as the sun,\nWe've no less days to sing God's praise\nThan when we first begun.",
"V6" "v6"
] ]
] ]
} }

View File

@ -0,0 +1,44 @@
{
"title": "BBBBBBBBB",
"authors": [
"John Newton (1725-1807)"
],
"verses": [
[
"V1V1V1V1V1V1\nV1V1V1V1V1V1",
"v1"
],
[
"V2V2V2V2V2V2\nV2V2V2V2V2V2",
"v2"
],
[
"C1C1C1C1C1C1\nC1C1C1C1C1C1",
"c1"
],
[
"C2C2C2C2C2C2\nC2C2C2C2C2C2",
"c2"
],
[
"B1B1B1B1B1B1\nB1B1B1B1B1B1",
"b1"
],
[
"B2B2B2B2B2B2\nB2B2B2B2B2B2",
"b2"
],
[
"PRE1PRE1PRE1\nPRE1PRE1PRE1",
"p1"
],
[
"PRE2PRE2PRE2\nPRE2PRE2PRE2",
"p2"
],
[
"ENDENDENDEND\nENDENDENDEND",
"e1"
]
]
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<EasiSlides>
<Item>
<Title1>BBBBBBBBB</Title1>
<Title2 />
<Folder>NAGY</Folder>
<SongNumber>0</SongNumber>
<Contents>[1]
V1V1V1V1V1V1
V1V1V1V1V1V1
[2]
V2V2V2V2V2V2
V2V2V2V2V2V2
[chorus]
C1C1C1C1C1C1
C1C1C1C1C1C1
[chorus 2]
C2C2C2C2C2C2
C2C2C2C2C2C2
[bridge]
B1B1B1B1B1B1
B1B1B1B1B1B1
[bridge 2]
B2B2B2B2B2B2
B2B2B2B2B2B2
[prechorus]
PRE1PRE1PRE1
PRE1PRE1PRE1
[prechorus 2]
PRE2PRE2PRE2
PRE2PRE2PRE2
[ending]
ENDENDENDEND
ENDENDENDEND</Contents>
<Notations />
<Sequence>1,2,c,t,b,w,p,q,e</Sequence>
<Writer />
<Copyright />
<Category />
<Timing />
<MusicKey />
<Capo>-1</Capo>
<LicenceAdmin1 />
<LicenceAdmin2 />
<BookReference />
<UserReference />
<FormatData />
<Settings>10=&gt;</Settings>
</Item>
</EasiSlides>

View File

@ -1,4 +1,4 @@
{Abbreviation:"SB1",Copyright:"Public domain",Songs:[{ID:3,Composer:"Unknown",Author:"Martin Luther",Copyright:"Public {Abbreviation:"SB1",Copyright:"Public domain",Songs:[{ID:3,Composer:"Unknown",Author:"Martin Luther",Capo:-1,Copyright:"Public
Domain",Theme:"tema1 Domain",Theme:"tema1
tema2",CCLI:"12345",Alias:"A safe stronghold",Memo1:"This is tema2",CCLI:"12345",Alias:"A safe stronghold",Memo1:"This is
the first comment the first comment