From 0645754d5742c955965d35cdbd617d550f959146 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 13:19:24 +0100
Subject: [wip] Generate RSS feed from concerts list
---
build-feed.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100755 build-feed.py
diff --git a/build-feed.py b/build-feed.py
new file mode 100755
index 0000000..5b14326
--- /dev/null
+++ b/build-feed.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+
+from urllib.parse import urljoin
+from xml.etree.ElementTree import Element, SubElement, indent, tostring
+
+
+DOMAIN = 'quatuorbellefeuille.com'
+LANG = 'fr'
+
+
+LOCALIZED_TEXT = {
+ 'en': {
+ 'title': 'Bellefeuille Quartet',
+ 'indexpath': 'en/',
+ 'description': 'News from the Bellefeuille quartet',
+ },
+ 'fr': {
+ 'title': 'Quatuor Bellefeuille',
+ 'indexpath': '/',
+ 'description': 'Des nouvelles du quatuor Bellefeuille',
+ },
+}
+
+URL = f'https://{DOMAIN}'
+INDEX_URL = urljoin(URL, LOCALIZED_TEXT[LANG]['indexpath'])
+
+
+def text_element(tag, text, /, **kwargs):
+ elt = Element(tag, **kwargs)
+ elt.text = text
+ return elt
+
+
+rss = Element('rss', version='2.0')
+
+channel = SubElement(rss, 'channel')
+
+channel.extend((
+ text_element('title', LOCALIZED_TEXT[LANG]['title']),
+ text_element('link', INDEX_URL),
+ text_element('description', LOCALIZED_TEXT[LANG]['description']),
+))
+
+image = SubElement(channel, 'image')
+image.extend((
+ text_element('url', urljoin(URL, 'images/logo.svg')),
+ text_element('link', urljoin(INDEX_URL, 'concerts.html')),
+))
+
+channel.append(text_element('language', LANG))
+
+indent(rss)
+
+print(tostring(rss, encoding='utf-8', xml_declaration=True).decode())
--
cgit v1.2.3
From 6d9636d35c5d0d244208165010bb70635c98ab2c Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 15:18:39 +0100
Subject: Move some concert stuff to common helpers
The RSS builder will need it.
---
build-concerts.py | 114 +-----------------------------------------------------
helpers.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 113 deletions(-)
diff --git a/build-concerts.py b/build-concerts.py
index 43dce57..7b0f75d 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -1,16 +1,13 @@
#!/usr/bin/env python3
from contextlib import contextmanager
-from dataclasses import dataclass
from datetime import datetime
import locale
-from operator import attrgetter
from pathlib import Path
import re
from sys import argv
-from typing import Iterator, Optional
-from helpers import relative_path
+from helpers import guess_language, read_concerts, relative_path
# TODO: change some jargon:
@@ -18,115 +15,6 @@ from helpers import relative_path
# - canceled => warning
-LICENSE_URLS = {
- 'CC0': 'https://creativecommons.org/publicdomain/zero',
- 'CC BY': 'https://creativecommons.org/licenses/by',
- 'CC BY-SA': 'https://creativecommons.org/licenses/by-sa',
-}
-
-LICENSE_RE = re.compile(
- '('+'|'.join(LICENSE_URLS.keys())+')' + ' ([0-9.]+)'
-)
-
-
-@dataclass
-class LicenseInfo:
- tag: str
- version: str
-
- @classmethod
- def deserialize(cls, info):
- if info is None:
- return None
- return cls(*LICENSE_RE.fullmatch(info).groups())
-
- def format(self):
- url = f'{LICENSE_URLS[self.tag]}/{self.version}/'
-
- return f'{self.tag} '
-
-
-@dataclass
-class Illustration:
- file: str
- alt_text: str
- source_name: str
- source_link: Optional[str]
- license_info: Optional[LicenseInfo]
-
- @classmethod
- def deserialize(cls, d):
- return cls(d['pic_file'],
- d['pic_alt'],
- d['pic_src'],
- d['pic_link'],
- LicenseInfo.deserialize(d['pic_license']))
-
-
-@dataclass
-class Concert:
- time: datetime
- place: str
- address: str
- pieces: Iterator[str]
- instructions: str
- illustration: Illustration
- warning: Optional[str]
-
- @classmethod
- def deserialize(cls, d):
- return cls(
- time=datetime.strptime(d['time'], '%d/%m/%Y %Hh%M'),
- place=d['place'],
- address=d['address'],
- pieces=d['pieces'],
- instructions=d['instructions'],
- illustration=Illustration.deserialize(d),
- warning=d['warning']
- )
-
-
-def optional(line):
- return f'(?:{line})?'
-
-
-CONCERT_LINES = (
- r'QUAND : (?P[^\n]+)\n',
- r'O[UÙ] : (?P[^\n]+)\n',
- 'ADRESSE :\n',
- '(?P.+?)\n',
- 'PROGRAMME :\n',
- '(?P.+?)\n',
- 'INSTRUCTIONS :\n',
- '(?P.+?)\n',
- 'ILLUSTRATION :\n',
- r'fichier : (?P[^\n]+)\n',
- r'légende : (?P[^\n]+)\n',
- r'source : (?P[^\n]+)\n',
- optional(r'lien : (?P[^\n]+)\n'),
- optional(r'licence : (?P[^\n]+)\n'),
- optional(r'AVERTISSEMENT : (?P[^\n]+)\n'),
-)
-
-CONCERT_RE = re.compile(''.join(CONCERT_LINES), flags=re.DOTALL)
-
-
-def guess_language(filename):
- parent = str(Path(filename).parent)
- if parent == '.':
- return 'fr'
- return parent
-
-
-def read_concerts(filename):
- with open(filename) as f:
- concerts = (
- Concert.deserialize(match)
- for match in re.finditer(CONCERT_RE, f.read())
- )
- return tuple(sorted(concerts, key=attrgetter('time')))
-
-
def split_concerts(concerts, threshold):
cutoff = len(concerts)
diff --git a/helpers.py b/helpers.py
index faf14e7..162d39e 100644
--- a/helpers.py
+++ b/helpers.py
@@ -1,5 +1,17 @@
+from dataclasses import dataclass
+from datetime import datetime
+from operator import attrgetter
from os import path
from pathlib import Path
+import re
+from typing import Iterator, Optional
+
+
+def guess_language(filename):
+ parent = str(Path(filename).parent)
+ if parent == '.':
+ return 'fr'
+ return parent
def relative_path(*, to, ref):
@@ -7,3 +19,103 @@ def relative_path(*, to, ref):
# os.path.dirname('x') yields '' rather than '.'.
# 😮💨
return path.relpath(to, Path(ref).parent)
+
+
+_LICENSE_URLS = {
+ 'CC0': 'https://creativecommons.org/publicdomain/zero',
+ 'CC BY': 'https://creativecommons.org/licenses/by',
+ 'CC BY-SA': 'https://creativecommons.org/licenses/by-sa',
+}
+
+_LICENSE_RE = re.compile(
+ '('+'|'.join(_LICENSE_URLS.keys())+')' + ' ([0-9.]+)'
+)
+
+@dataclass
+class LicenseInfo:
+ tag: str
+ version: str
+
+ @classmethod
+ def deserialize(cls, info):
+ if info is None:
+ return None
+ return cls(*_LICENSE_RE.fullmatch(info).groups())
+
+ def format(self):
+ url = f'{_LICENSE_URLS[self.tag]}/{self.version}/'
+
+ return f'{self.tag} '
+
+
+@dataclass
+class Illustration:
+ file: str
+ alt_text: str
+ source_name: str
+ source_link: Optional[str]
+ license_info: Optional[LicenseInfo]
+
+ @classmethod
+ def deserialize(cls, d):
+ return cls(d['pic_file'],
+ d['pic_alt'],
+ d['pic_src'],
+ d['pic_link'],
+ LicenseInfo.deserialize(d['pic_license']))
+
+
+@dataclass
+class Concert:
+ time: datetime
+ place: str
+ address: str
+ pieces: Iterator[str]
+ instructions: str
+ illustration: Illustration
+ warning: Optional[str]
+
+ @classmethod
+ def deserialize(cls, d):
+ return cls(
+ time=datetime.strptime(d['time'], '%d/%m/%Y %Hh%M'),
+ place=d['place'],
+ address=d['address'],
+ pieces=d['pieces'],
+ instructions=d['instructions'],
+ illustration=Illustration.deserialize(d),
+ warning=d['warning']
+ )
+
+
+def _optional(line):
+ return f'(?:{line})?'
+
+_CONCERT_LINES = (
+ r'QUAND : (?P[^\n]+)\n',
+ r'O[UÙ] : (?P[^\n]+)\n',
+ 'ADRESSE :\n',
+ '(?P.+?)\n',
+ 'PROGRAMME :\n',
+ '(?P.+?)\n',
+ 'INSTRUCTIONS :\n',
+ '(?P.+?)\n',
+ 'ILLUSTRATION :\n',
+ r'fichier : (?P[^\n]+)\n',
+ r'légende : (?P[^\n]+)\n',
+ r'source : (?P[^\n]+)\n',
+ _optional(r'lien : (?P[^\n]+)\n'),
+ _optional(r'licence : (?P[^\n]+)\n'),
+ _optional(r'AVERTISSEMENT : (?P[^\n]+)\n'),
+)
+
+_CONCERT_RE = re.compile(''.join(_CONCERT_LINES), flags=re.DOTALL)
+
+
+def read_concerts(filename):
+ with open(filename) as f:
+ concerts = (
+ Concert.deserialize(match)
+ for match in re.finditer(_CONCERT_RE, f.read())
+ )
+ return tuple(sorted(concerts, key=attrgetter('time')))
--
cgit v1.2.3
From 8ea5a391e289c4e35995b00b9ef5ec91a26cb5d7 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 15:44:44 +0100
Subject: [wip] Reorganize RSS builder code
---
build-feed.py | 50 +++++++++++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 21 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index 5b14326..7295563 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -1,11 +1,10 @@
#!/usr/bin/env python3
+from sys import argv
from urllib.parse import urljoin
from xml.etree.ElementTree import Element, SubElement, indent, tostring
-
-DOMAIN = 'quatuorbellefeuille.com'
-LANG = 'fr'
+from helpers import guess_language
LOCALIZED_TEXT = {
@@ -21,9 +20,6 @@ LOCALIZED_TEXT = {
},
}
-URL = f'https://{DOMAIN}'
-INDEX_URL = urljoin(URL, LOCALIZED_TEXT[LANG]['indexpath'])
-
def text_element(tag, text, /, **kwargs):
elt = Element(tag, **kwargs)
@@ -31,24 +27,36 @@ def text_element(tag, text, /, **kwargs):
return elt
-rss = Element('rss', version='2.0')
+def main(concerts_src, feed_dst, domain):
+ lang = guess_language(concerts_src)
+ text = LOCALIZED_TEXT[lang]
+
+ url = f'https://{domain}'
+ index_url = urljoin(url, text['indexpath'])
+
+ rss = Element('rss', version='2.0')
+
+ channel = SubElement(rss, 'channel')
+
+ channel.extend((
+ text_element('title', text['title']),
+ text_element('link', index_url),
+ text_element('description', text['description']),
+ ))
-channel = SubElement(rss, 'channel')
+ image = SubElement(channel, 'image')
+ image.extend((
+ text_element('url', urljoin(url, 'images/logo.svg')),
+ text_element('link', urljoin(index_url, 'concerts.html')),
+ ))
-channel.extend((
- text_element('title', LOCALIZED_TEXT[LANG]['title']),
- text_element('link', INDEX_URL),
- text_element('description', LOCALIZED_TEXT[LANG]['description']),
-))
+ channel.append(text_element('language', lang))
-image = SubElement(channel, 'image')
-image.extend((
- text_element('url', urljoin(URL, 'images/logo.svg')),
- text_element('link', urljoin(INDEX_URL, 'concerts.html')),
-))
+ indent(rss)
-channel.append(text_element('language', LANG))
+ with open(feed_dst, 'wb') as feed:
+ feed.write(tostring(rss, encoding='utf-8', xml_declaration=True))
-indent(rss)
-print(tostring(rss, encoding='utf-8', xml_declaration=True).decode())
+if __name__ == '__main__':
+ main(argv[1], argv[2], argv[3])
--
cgit v1.2.3
From 28ef8c28422882150bef4874b3030321aff8add0 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 16:18:30 +0100
Subject: [wip] Make list of concert items in RSS feed
---
build-concerts.py | 14 +-------------
build-feed.py | 28 +++++++++++++++++++++++++++-
helpers.py | 12 ++++++++++++
3 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/build-concerts.py b/build-concerts.py
index 7b0f75d..d1a7c11 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -1,13 +1,11 @@
#!/usr/bin/env python3
-from contextlib import contextmanager
from datetime import datetime
-import locale
from pathlib import Path
import re
from sys import argv
-from helpers import guess_language, read_concerts, relative_path
+from helpers import guess_language, read_concerts, relative_path, tmplocale
# TODO: change some jargon:
@@ -65,16 +63,6 @@ THUMBNAIL_TEMPLATE = '''\
'''
-@contextmanager
-def tmplocale(lang):
- old_lang, encoding = locale.getlocale()
- try:
- locale.setlocale(locale.LC_TIME, (lang, encoding))
- yield
- finally:
- locale.setlocale(locale.LC_TIME, (old_lang, encoding))
-
-
def format_credits(illustration):
credits = illustration.source_name
diff --git a/build-feed.py b/build-feed.py
index 7295563..e2c8244 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -4,7 +4,7 @@ from sys import argv
from urllib.parse import urljoin
from xml.etree.ElementTree import Element, SubElement, indent, tostring
-from helpers import guess_language
+from helpers import guess_language, read_concerts, tmplocale
LOCALIZED_TEXT = {
@@ -20,6 +20,15 @@ LOCALIZED_TEXT = {
},
}
+LOCALIZED_FORMATS = {
+ 'en': {
+ 'title': lambda c: f'{c.time.strftime("%B %-d %Y")} in {c.place}',
+ },
+ 'fr': {
+ 'title': lambda c: f'{c.time.strftime("%-d %B %Y")} à {c.place}',
+ },
+}
+
def text_element(tag, text, /, **kwargs):
elt = Element(tag, **kwargs)
@@ -27,6 +36,20 @@ def text_element(tag, text, /, **kwargs):
return elt
+def generate_concerts(concerts_src, lang):
+ formatters = LOCALIZED_FORMATS[lang]
+
+ for c in read_concerts(concerts_src):
+ item = Element('item')
+
+ with tmplocale(lang):
+ title = formatters['title'](c)
+
+ item.append(text_element('title', title))
+
+ yield item
+
+
def main(concerts_src, feed_dst, domain):
lang = guess_language(concerts_src)
text = LOCALIZED_TEXT[lang]
@@ -52,6 +75,9 @@ def main(concerts_src, feed_dst, domain):
channel.append(text_element('language', lang))
+ items = generate_concerts(concerts_src, lang)
+ channel.extend(tuple(items))
+
indent(rss)
with open(feed_dst, 'wb') as feed:
diff --git a/helpers.py b/helpers.py
index 162d39e..87ed9c1 100644
--- a/helpers.py
+++ b/helpers.py
@@ -1,5 +1,7 @@
+from contextlib import contextmanager
from dataclasses import dataclass
from datetime import datetime
+import locale
from operator import attrgetter
from os import path
from pathlib import Path
@@ -21,6 +23,16 @@ def relative_path(*, to, ref):
return path.relpath(to, Path(ref).parent)
+@contextmanager
+def tmplocale(lang):
+ old_lang, encoding = locale.getlocale()
+ try:
+ locale.setlocale(locale.LC_TIME, (lang, encoding))
+ yield
+ finally:
+ locale.setlocale(locale.LC_TIME, (old_lang, encoding))
+
+
_LICENSE_URLS = {
'CC0': 'https://creativecommons.org/publicdomain/zero',
'CC BY': 'https://creativecommons.org/licenses/by',
--
cgit v1.2.3
From 836aaf1fdfa5a60d261ed6e06e880d08b1b68bd0 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 19:11:20 +0100
Subject: [wip] Make list of concert items in RSS feed (cont'd)
---
build-feed.py | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index e2c8244..d3409f9 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -36,18 +36,25 @@ def text_element(tag, text, /, **kwargs):
return elt
-def generate_concerts(concerts_src, lang):
+def generate_concert(concert, concerts_url, lang):
formatters = LOCALIZED_FORMATS[lang]
- for c in read_concerts(concerts_src):
- item = Element('item')
+ item = Element('item')
+
+ with tmplocale(lang):
+ title = formatters['title'](concert)
+ item.append(text_element('title', title))
+
+ anchor = f'concert-{concert.time.strftime("%F")}'
+ item.append(text_element('link', f'{concerts_url}#{anchor}'))
- with tmplocale(lang):
- title = formatters['title'](c)
+ return item
- item.append(text_element('title', title))
- yield item
+def generate_concerts(concerts_src, concerts_url, lang):
+
+ for c in read_concerts(concerts_src):
+ yield generate_concert(c, concerts_url, lang)
def main(concerts_src, feed_dst, domain):
@@ -56,6 +63,7 @@ def main(concerts_src, feed_dst, domain):
url = f'https://{domain}'
index_url = urljoin(url, text['indexpath'])
+ concerts_url = urljoin(index_url, 'concerts.html')
rss = Element('rss', version='2.0')
@@ -70,12 +78,12 @@ def main(concerts_src, feed_dst, domain):
image = SubElement(channel, 'image')
image.extend((
text_element('url', urljoin(url, 'images/logo.svg')),
- text_element('link', urljoin(index_url, 'concerts.html')),
+ text_element('link', concerts_url),
))
channel.append(text_element('language', lang))
- items = generate_concerts(concerts_src, lang)
+ items = generate_concerts(concerts_src, concerts_url, lang)
channel.extend(tuple(items))
indent(rss)
--
cgit v1.2.3
From 5876793d01ab2e392e93eec9323dd6a7edb53170 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 19:57:49 +0100
Subject: Extract more stuff out of build-concerts.py
---
build-concerts.py | 22 +++++++---------------
helpers.py | 14 ++++++++++++++
2 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/build-concerts.py b/build-concerts.py
index d1a7c11..0e5a70b 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -5,7 +5,13 @@ from pathlib import Path
import re
from sys import argv
-from helpers import guess_language, read_concerts, relative_path, tmplocale
+from helpers import (
+ guess_language,
+ read_concerts,
+ relative_path,
+ tmplocale,
+ touchup_plaintext,
+)
# TODO: change some jargon:
@@ -162,20 +168,6 @@ def break_lines(lines):
return tuple(line+' ' for line in lines[:-1]) + (lines[-1],)
-TOUCHUPS = (
- (re.compile('([0-9])(st|nd|rd|th|er|ère|nde|ème)'), r'\1\2 '),
- (re.compile('(https://[^ ]+)'), r'\1 '),
- (re.compile('([^ ]+@[^ ]+)'), r'\1 '),
-)
-
-
-def touchup_plaintext(plaintext):
- text = plaintext
- for regexp, repl in TOUCHUPS:
- text = regexp.sub(repl, text)
- return text
-
-
def print_concert_details(concert, lang):
concert_id = f'concert-{concert.time.strftime("%F")}'
classes = ('details',)
diff --git a/helpers.py b/helpers.py
index 87ed9c1..a746ea2 100644
--- a/helpers.py
+++ b/helpers.py
@@ -131,3 +131,17 @@ def read_concerts(filename):
for match in re.finditer(_CONCERT_RE, f.read())
)
return tuple(sorted(concerts, key=attrgetter('time')))
+
+
+_TOUCHUPS = (
+ (re.compile('([0-9])(st|nd|rd|th|er|ère|nde|ème)'), r'\1\2 '),
+ (re.compile('(https://[^ ]+)'), r'\1 '),
+ (re.compile('([^ ]+@[^ ]+)'), r'\1 '),
+)
+
+
+def touchup_plaintext(plaintext):
+ text = plaintext
+ for regexp, repl in _TOUCHUPS:
+ text = regexp.sub(repl, text)
+ return text
--
cgit v1.2.3
From 0729fb76b52dcdaaf6d9b7f4dd60bc0099f067c3 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Mon, 21 Feb 2022 21:22:10 +0100
Subject: [wip] Add CDATA
Doesn't work yet, the tags get escaped. Maybe lxml has a simpler API?
---
build-concerts.py | 13 +------------
build-feed.py | 45 +++++++++++++++++++++++++++++++++++++++++++--
helpers.py | 12 ++++++++++++
3 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/build-concerts.py b/build-concerts.py
index 0e5a70b..4f55f12 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -6,6 +6,7 @@ import re
from sys import argv
from helpers import (
+ DATE_FORMATTERS,
guess_language,
read_concerts,
relative_path,
@@ -138,18 +139,6 @@ DETAILS_TEMPLATE = '''\
'''
-DATE_FORMATTERS = {
- 'en': {
- 'date': lambda d: d.strftime('%A %B %-d, %Y'),
- 'time': lambda d: d.strftime('%I:%M %P'),
- },
- 'fr': {
- 'date': lambda d: d.strftime('%A %-d %B %Y').capitalize(),
- 'time': lambda d: d.strftime('%Hh%M'),
- },
-}
-
-
def detail_block(tag, classes, content):
opener = f'<{tag} class="{" ".join(classes)}">'
closer = f'{tag}>'
diff --git a/build-feed.py b/build-feed.py
index d3409f9..a8cb733 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -4,7 +4,13 @@ from sys import argv
from urllib.parse import urljoin
from xml.etree.ElementTree import Element, SubElement, indent, tostring
-from helpers import guess_language, read_concerts, tmplocale
+from helpers import (
+ DATE_FORMATTERS,
+ guess_language,
+ read_concerts,
+ tmplocale,
+ touchup_plaintext,
+)
LOCALIZED_TEXT = {
@@ -36,6 +42,39 @@ def text_element(tag, text, /, **kwargs):
return elt
+def block(tag, content):
+ return f'<{tag}>{content}{tag}>'
+
+
+def cdata_concert(concert, lang):
+ formatters = DATE_FORMATTERS[lang]
+
+ blocks = []
+
+ if concert.warning is None:
+ blocks.append(block('p', concert.warning))
+
+ blocks.extend((
+ block('p', formatters['date'](concert.time)),
+ block('p', formatters['time'](concert.time)),
+ block('p', concert.address.replace('\n', ' '))
+ ))
+
+ piece_list = '\n'.join(
+ block('li', touchup_plaintext(p)) for p in concert.pieces.splitlines()
+ )
+ blocks.append(block('ol', piece_list))
+
+ blocks.extend(
+ block('p', touchup_plaintext(line))
+ for line in concert.instructions.splitlines()
+ )
+
+ cdata = '\n'.join((blocks))
+
+ return f'
Date: Mon, 21 Feb 2022 22:09:12 +0100
Subject: [wip] Add CDATA (cont'd)
---
build-feed.py | 98 ++++++++++++++++++++++++-----------------------------------
1 file changed, 39 insertions(+), 59 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index a8cb733..a6b0890 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -2,7 +2,9 @@
from sys import argv
from urllib.parse import urljoin
-from xml.etree.ElementTree import Element, SubElement, indent, tostring
+
+from lxml.builder import E
+from lxml.etree import CDATA, indent, tostring
from helpers import (
DATE_FORMATTERS,
@@ -36,66 +38,50 @@ LOCALIZED_FORMATS = {
}
-def text_element(tag, text, /, **kwargs):
- elt = Element(tag, **kwargs)
- elt.text = text
- return elt
-
-
-def block(tag, content):
- return f'<{tag}>{content}{tag}>'
-
-
def cdata_concert(concert, lang):
formatters = DATE_FORMATTERS[lang]
blocks = []
- if concert.warning is None:
- blocks.append(block('p', concert.warning))
+ if concert.warning is not None:
+ blocks.append(E.p(concert.warning))
blocks.extend((
- block('p', formatters['date'](concert.time)),
- block('p', formatters['time'](concert.time)),
- block('p', concert.address.replace('\n', ' '))
+ E.p(formatters['date'](concert.time)),
+ E.p(formatters['time'](concert.time)),
+ # TODO: NEED TO USE FUNC/ITERTOOLS SHENANIGANS TO WEAVE E.br INTO THIS
+ E.p(concert.address.replace('\n', ' ')),
+ E.ol(
+ *(E.li(touchup_plaintext(p)) for p in concert.pieces.splitlines())
+ ),
+ *tuple(E.p(line) for line in concert.instructions.splitlines()),
))
- piece_list = '\n'.join(
- block('li', touchup_plaintext(p)) for p in concert.pieces.splitlines()
- )
- blocks.append(block('ol', piece_list))
-
- blocks.extend(
- block('p', touchup_plaintext(line))
- for line in concert.instructions.splitlines()
- )
-
- cdata = '\n'.join((blocks))
-
- return f'
Date: Tue, 22 Feb 2022 12:51:48 +0100
Subject: [wip] Add CDATA (cont'd and over)
Now we just need to add the publication date.
---
build-feed.py | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index a6b0890..e200920 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -38,6 +38,19 @@ LOCALIZED_FORMATS = {
}
+def join(sequence, joiner_factory):
+ # There's got to be a standard itertools/functools thingy to do that…
+ result = []
+
+ for i, item in enumerate(sequence, start=1):
+ result.append(item)
+
+ if i == len(sequence):
+ return result
+
+ result.append(joiner_factory())
+
+
def cdata_concert(concert, lang):
formatters = DATE_FORMATTERS[lang]
@@ -49,8 +62,7 @@ def cdata_concert(concert, lang):
blocks.extend((
E.p(formatters['date'](concert.time)),
E.p(formatters['time'](concert.time)),
- # TODO: NEED TO USE FUNC/ITERTOOLS SHENANIGANS TO WEAVE E.br INTO THIS
- E.p(concert.address.replace('\n', ' ')),
+ E.p(*join(concert.address.splitlines(), E.br)),
E.ol(
*(E.li(touchup_plaintext(p)) for p in concert.pieces.splitlines())
),
--
cgit v1.2.3
From 34c2911036b8fc197ea309f2c34516800441916b Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Tue, 22 Feb 2022 13:20:01 +0100
Subject: [wip] Add CDATA (post-credits stinger)
---
build-feed.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build-feed.py b/build-feed.py
index e200920..3e56576 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -66,7 +66,7 @@ def cdata_concert(concert, lang):
E.ol(
*(E.li(touchup_plaintext(p)) for p in concert.pieces.splitlines())
),
- *tuple(E.p(line) for line in concert.instructions.splitlines()),
+ *(E.p(line) for line in concert.instructions.splitlines()),
))
return CDATA('\n'.join(
--
cgit v1.2.3
From 1bb633ff40d2e3f4994f8c40d8dfd005920f3562 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Tue, 22 Feb 2022 19:19:32 +0100
Subject: [wip] Add channel pubDate and lastBuildDate
---
build-feed.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/build-feed.py b/build-feed.py
index 3e56576..fb85cab 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
+from datetime import datetime
from sys import argv
from urllib.parse import urljoin
@@ -15,6 +16,13 @@ from helpers import (
)
+TIMEZONE = datetime.now().astimezone().tzinfo
+NOW = datetime.now(tz=TIMEZONE)
+DATE_FORMAT = '%-d %b %Y %H:%M %z'
+
+# TODO: add item pubDate
+
+
LOCALIZED_TEXT = {
'en': {
'title': 'Bellefeuille Quartet',
@@ -104,6 +112,8 @@ def main(concerts_src, feed_dst, domain):
index_url = urljoin(url, text['indexpath'])
concerts_url = urljoin(index_url, 'concerts.html')
+ now_formatted = NOW.strftime(DATE_FORMAT)
+
rss = E.rss(
E.channel(
E.title(text['title']),
@@ -113,6 +123,8 @@ def main(concerts_src, feed_dst, domain):
E.url(urljoin(url, 'images/logo.svg')),
E.link(concerts_url),
),
+ E.lastBuildDate(now_formatted),
+ E.pubDate(now_formatted),
E.language(lang),
*generate_concerts(concerts_src, concerts_url, lang),
),
--
cgit v1.2.3
From 9372b46a1636eb6b18b3df627eb62b324dfce3f6 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Tue, 22 Feb 2022 22:24:31 +0100
Subject: [wip] Add publication dates
---
build-feed.py | 57 +++++++++++++++++++++++++++++++++++++++++---------
concerts-pubdates.json | 15 +++++++++++++
2 files changed, 62 insertions(+), 10 deletions(-)
create mode 100644 concerts-pubdates.json
diff --git a/build-feed.py b/build-feed.py
index fb85cab..2359344 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python3
from datetime import datetime
+import json
+import re
from sys import argv
from urllib.parse import urljoin
@@ -16,6 +18,20 @@ from helpers import (
)
+# TODO: handle timezones correctly.
+# Places to disambiguate:
+#
+# - concerts.in:
+# either add the zone explicitly, or deduce it from the place,
+# assuming all times in concerts.in are local times.
+#
+# - concerts-pubdates.json:
+# just add the zone explicitly.
+#
+# Until then, assume all these "naive times" describe the same timezone
+# (CET/CEST).
+
+
TIMEZONE = datetime.now().astimezone().tzinfo
NOW = datetime.now(tz=TIMEZONE)
DATE_FORMAT = '%-d %b %Y %H:%M %z'
@@ -59,6 +75,9 @@ def join(sequence, joiner_factory):
result.append(joiner_factory())
+CDATA_INDENT = 8*' '
+
+
def cdata_concert(concert, lang):
formatters = DATE_FORMATTERS[lang]
@@ -77,12 +96,15 @@ def cdata_concert(concert, lang):
*(E.p(line) for line in concert.instructions.splitlines()),
))
- return CDATA('\n'.join(
- tostring(b, encoding='utf-8').decode() for b in blocks
- ))
+ html_blocks = (tostring(b, encoding='utf-8').decode() for b in blocks)
+
+ cdata = '\n' + '\n'.join(html_blocks) + '\n'
+ cdata = re.sub('^', CDATA_INDENT, cdata, flags=re.MULTILINE)
+
+ return CDATA(cdata)
-def generate_concert(concert, concerts_url, lang):
+def generate_concert(concert, concerts_url, pubdates, lang):
formatters = LOCALIZED_FORMATS[lang]
with tmplocale(lang):
@@ -90,21 +112,32 @@ def generate_concert(concert, concerts_url, lang):
anchor = f'concert-{concert.time.strftime("%F")}'
- return E.item(
+ item = E.item(
E.title(title),
E.link(f'{concerts_url}#{anchor}'),
E.description(cdata_concert(concert, lang)),
)
+ pubdate_str = pubdates[concert.time.isoformat(timespec='minutes')]
+
+ if pubdate_str is not None:
+ pubdate = datetime.fromisoformat(pubdate_str).replace(tzinfo=TIMEZONE)
+ item.append(E.pubDate(pubdate.strftime(DATE_FORMAT)))
+
+ return item
+
+
+def generate_concerts(concerts_src, concerts_url, concerts_pubdates, lang):
+ with open(concerts_pubdates) as pubdates_file:
+ pubdates = json.load(pubdates_file)
-def generate_concerts(concerts_src, concerts_url, lang):
return tuple(
- generate_concert(c, concerts_url, lang)
+ generate_concert(c, concerts_url, pubdates, lang)
for c in read_concerts(concerts_src)
)
-def main(concerts_src, feed_dst, domain):
+def main(concerts_src, feed_dst, concerts_pubdates, domain):
lang = guess_language(concerts_src)
text = LOCALIZED_TEXT[lang]
@@ -114,6 +147,10 @@ def main(concerts_src, feed_dst, domain):
now_formatted = NOW.strftime(DATE_FORMAT)
+ concerts = generate_concerts(
+ concerts_src, concerts_url, concerts_pubdates, lang
+ )
+
rss = E.rss(
E.channel(
E.title(text['title']),
@@ -126,7 +163,7 @@ def main(concerts_src, feed_dst, domain):
E.lastBuildDate(now_formatted),
E.pubDate(now_formatted),
E.language(lang),
- *generate_concerts(concerts_src, concerts_url, lang),
+ *concerts,
),
version='2.0',
)
@@ -138,4 +175,4 @@ def main(concerts_src, feed_dst, domain):
if __name__ == '__main__':
- main(argv[1], argv[2], argv[3])
+ main(*argv[1:])
diff --git a/concerts-pubdates.json b/concerts-pubdates.json
new file mode 100644
index 0000000..4232ed7
--- /dev/null
+++ b/concerts-pubdates.json
@@ -0,0 +1,15 @@
+{
+ "2019-10-05T17:00": null,
+ "2019-10-06T16:00": null,
+ "2020-03-08T16:00": null,
+ "2020-08-24T20:00": null,
+ "2021-04-03T20:00": "2021-03-19T16:00",
+ "2021-06-13T15:00": "2021-03-19T16:00",
+ "2021-08-17T20:30": null,
+ "2021-08-19T20:00": null,
+ "2021-10-25T18:00": null,
+ "2021-10-28T18:00": null,
+ "2021-12-12T16:00": "2021-11-23T23:28",
+ "2021-12-31T20:00": null,
+ "2022-05-07T17:00": null
+}
--
cgit v1.2.3
From 099395ed6f5b3694c0c733293c241140089cbfe7 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Tue, 22 Feb 2022 22:39:18 +0100
Subject: [wip] Make sure "touched up" plaintext is not mangled
---
build-feed.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index 2359344..d6de058 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -7,7 +7,7 @@ from sys import argv
from urllib.parse import urljoin
from lxml.builder import E
-from lxml.etree import CDATA, indent, tostring
+from lxml.etree import CDATA, XML, indent, tostring
from helpers import (
DATE_FORMATTERS,
@@ -75,6 +75,14 @@ def join(sequence, joiner_factory):
result.append(joiner_factory())
+def piece_list(pieces):
+ ol_list = E.ol(
+ *(XML(f'{touchup_plaintext(p)} ') for p in pieces)
+ )
+ indent(ol_list)
+ return ol_list
+
+
CDATA_INDENT = 8*' '
@@ -90,9 +98,7 @@ def cdata_concert(concert, lang):
E.p(formatters['date'](concert.time)),
E.p(formatters['time'](concert.time)),
E.p(*join(concert.address.splitlines(), E.br)),
- E.ol(
- *(E.li(touchup_plaintext(p)) for p in concert.pieces.splitlines())
- ),
+ piece_list(concert.pieces.splitlines()),
*(E.p(line) for line in concert.instructions.splitlines()),
))
--
cgit v1.2.3
From a0ffc78d4661335d73e25edffad1f1d0fe095e7c Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Tue, 22 Feb 2022 22:57:45 +0100
Subject: [wip] Fix date formatting in RSS builder
---
build-feed.py | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/build-feed.py b/build-feed.py
index d6de058..5fe5c04 100755
--- a/build-feed.py
+++ b/build-feed.py
@@ -75,14 +75,6 @@ def join(sequence, joiner_factory):
result.append(joiner_factory())
-def piece_list(pieces):
- ol_list = E.ol(
- *(XML(f'{touchup_plaintext(p)} ') for p in pieces)
- )
- indent(ol_list)
- return ol_list
-
-
CDATA_INDENT = 8*' '
@@ -94,14 +86,24 @@ def cdata_concert(concert, lang):
if concert.warning is not None:
blocks.append(E.p(concert.warning))
+ with tmplocale(lang):
+ blocks.extend((
+ E.p(formatters['date'](concert.time)),
+ E.p(formatters['time'](concert.time)),
+ ))
+
blocks.extend((
- E.p(formatters['date'](concert.time)),
- E.p(formatters['time'](concert.time)),
E.p(*join(concert.address.splitlines(), E.br)),
- piece_list(concert.pieces.splitlines()),
+ E.ol(
+ *(XML(f'{touchup_plaintext(p)} ')
+ for p in concert.pieces.splitlines())
+ ),
*(E.p(line) for line in concert.instructions.splitlines()),
))
+ for b in blocks:
+ indent(b)
+
html_blocks = (tostring(b, encoding='utf-8').decode() for b in blocks)
cdata = '\n' + '\n'.join(html_blocks) + '\n'
--
cgit v1.2.3
From 66b5366b7b377f9e595ee9b97261b65a0064aa5b Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Wed, 23 Feb 2022 10:26:02 +0100
Subject: Add script to update feeds
---
Makefile | 20 +++-
admin/feeds/build-feed.py | 186 +++++++++++++++++++++++++++++++++++++
admin/feeds/build-feeds.sh | 19 ++++
admin/feeds/concerts-pubdates.json | 15 +++
build-feed.py | 186 -------------------------------------
build-feed.sh | 13 ---
concerts-pubdates.json | 15 ---
7 files changed, 235 insertions(+), 219 deletions(-)
create mode 100755 admin/feeds/build-feed.py
create mode 100755 admin/feeds/build-feeds.sh
create mode 100644 admin/feeds/concerts-pubdates.json
delete mode 100755 build-feed.py
delete mode 100755 build-feed.sh
delete mode 100644 concerts-pubdates.json
diff --git a/Makefile b/Makefile
index f3971d6..055daf8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+#################### Variables.
+
OUTDIR = public
dirname = $(patsubst %/,%,$(dir $(1)))
@@ -32,10 +34,21 @@ fonts_folders = $(call dirnames,$(fonts))
scripts = $(foreach img,$(shell find scripts -type f),$(OUTDIR)/$(img))
scripts_folders = $(call dirnames,$(scripts))
-.PHONY: all clean site upload
+#################### Top-level targets.
+
+# Building:
+.PHONY: all clean site
+
+# Maintenance:
+.PHONY: feeds upload
+
+#################### Recipes.
all: site
+feeds: $(feeds_folders)
+ ./admin/feeds/build-feeds.sh $(feeds_src)
+
upload: site
./upload.sh $(OUTDIR)
@@ -44,12 +57,9 @@ clean:
site: $(pages) $(members_pages) $(feeds) $(images) $(stylesheets) $(fonts) $(scripts)
-$(images) $(stylesheets) $(fonts) $(scripts): $(OUTDIR)/%: %
+$(images) $(stylesheets) $(fonts) $(scripts) $(feeds): $(OUTDIR)/%: %
cp $< $@
-$(feeds): $(OUTDIR)/%: %
- ./build-feed.sh $< $@
-
.SECONDEXPANSION:
# 🔪 HACK ATTACK 🔪
diff --git a/admin/feeds/build-feed.py b/admin/feeds/build-feed.py
new file mode 100755
index 0000000..5fe5c04
--- /dev/null
+++ b/admin/feeds/build-feed.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+
+from datetime import datetime
+import json
+import re
+from sys import argv
+from urllib.parse import urljoin
+
+from lxml.builder import E
+from lxml.etree import CDATA, XML, indent, tostring
+
+from helpers import (
+ DATE_FORMATTERS,
+ guess_language,
+ read_concerts,
+ tmplocale,
+ touchup_plaintext,
+)
+
+
+# TODO: handle timezones correctly.
+# Places to disambiguate:
+#
+# - concerts.in:
+# either add the zone explicitly, or deduce it from the place,
+# assuming all times in concerts.in are local times.
+#
+# - concerts-pubdates.json:
+# just add the zone explicitly.
+#
+# Until then, assume all these "naive times" describe the same timezone
+# (CET/CEST).
+
+
+TIMEZONE = datetime.now().astimezone().tzinfo
+NOW = datetime.now(tz=TIMEZONE)
+DATE_FORMAT = '%-d %b %Y %H:%M %z'
+
+# TODO: add item pubDate
+
+
+LOCALIZED_TEXT = {
+ 'en': {
+ 'title': 'Bellefeuille Quartet',
+ 'indexpath': 'en/',
+ 'description': 'News from the Bellefeuille quartet',
+ },
+ 'fr': {
+ 'title': 'Quatuor Bellefeuille',
+ 'indexpath': '/',
+ 'description': 'Des nouvelles du quatuor Bellefeuille',
+ },
+}
+
+LOCALIZED_FORMATS = {
+ 'en': {
+ 'title': lambda c: f'{c.time.strftime("%B %-d %Y")} in {c.place}',
+ },
+ 'fr': {
+ 'title': lambda c: f'{c.time.strftime("%-d %B %Y")} à {c.place}',
+ },
+}
+
+
+def join(sequence, joiner_factory):
+ # There's got to be a standard itertools/functools thingy to do that…
+ result = []
+
+ for i, item in enumerate(sequence, start=1):
+ result.append(item)
+
+ if i == len(sequence):
+ return result
+
+ result.append(joiner_factory())
+
+
+CDATA_INDENT = 8*' '
+
+
+def cdata_concert(concert, lang):
+ formatters = DATE_FORMATTERS[lang]
+
+ blocks = []
+
+ if concert.warning is not None:
+ blocks.append(E.p(concert.warning))
+
+ with tmplocale(lang):
+ blocks.extend((
+ E.p(formatters['date'](concert.time)),
+ E.p(formatters['time'](concert.time)),
+ ))
+
+ blocks.extend((
+ E.p(*join(concert.address.splitlines(), E.br)),
+ E.ol(
+ *(XML(f'{touchup_plaintext(p)} ')
+ for p in concert.pieces.splitlines())
+ ),
+ *(E.p(line) for line in concert.instructions.splitlines()),
+ ))
+
+ for b in blocks:
+ indent(b)
+
+ html_blocks = (tostring(b, encoding='utf-8').decode() for b in blocks)
+
+ cdata = '\n' + '\n'.join(html_blocks) + '\n'
+ cdata = re.sub('^', CDATA_INDENT, cdata, flags=re.MULTILINE)
+
+ return CDATA(cdata)
+
+
+def generate_concert(concert, concerts_url, pubdates, lang):
+ formatters = LOCALIZED_FORMATS[lang]
+
+ with tmplocale(lang):
+ title = formatters['title'](concert)
+
+ anchor = f'concert-{concert.time.strftime("%F")}'
+
+ item = E.item(
+ E.title(title),
+ E.link(f'{concerts_url}#{anchor}'),
+ E.description(cdata_concert(concert, lang)),
+ )
+
+ pubdate_str = pubdates[concert.time.isoformat(timespec='minutes')]
+
+ if pubdate_str is not None:
+ pubdate = datetime.fromisoformat(pubdate_str).replace(tzinfo=TIMEZONE)
+ item.append(E.pubDate(pubdate.strftime(DATE_FORMAT)))
+
+ return item
+
+
+def generate_concerts(concerts_src, concerts_url, concerts_pubdates, lang):
+ with open(concerts_pubdates) as pubdates_file:
+ pubdates = json.load(pubdates_file)
+
+ return tuple(
+ generate_concert(c, concerts_url, pubdates, lang)
+ for c in read_concerts(concerts_src)
+ )
+
+
+def main(concerts_src, feed_dst, concerts_pubdates, domain):
+ lang = guess_language(concerts_src)
+ text = LOCALIZED_TEXT[lang]
+
+ url = f'https://{domain}'
+ index_url = urljoin(url, text['indexpath'])
+ concerts_url = urljoin(index_url, 'concerts.html')
+
+ now_formatted = NOW.strftime(DATE_FORMAT)
+
+ concerts = generate_concerts(
+ concerts_src, concerts_url, concerts_pubdates, lang
+ )
+
+ rss = E.rss(
+ E.channel(
+ E.title(text['title']),
+ E.link(index_url),
+ E.description(text['description']),
+ E.image(
+ E.url(urljoin(url, 'images/logo.svg')),
+ E.link(concerts_url),
+ ),
+ E.lastBuildDate(now_formatted),
+ E.pubDate(now_formatted),
+ E.language(lang),
+ *concerts,
+ ),
+ version='2.0',
+ )
+
+ indent(rss)
+
+ with open(feed_dst, 'wb') as feed:
+ feed.write(tostring(rss, encoding='utf-8', xml_declaration=True))
+
+
+if __name__ == '__main__':
+ main(*argv[1:])
diff --git a/admin/feeds/build-feeds.sh b/admin/feeds/build-feeds.sh
new file mode 100755
index 0000000..99b4a6e
--- /dev/null
+++ b/admin/feeds/build-feeds.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -eu
+
+HERE=$(dirname "$0")
+ROOT=${HERE}/../..
+
+. "${ROOT}"/settings.sh
+
+FEEDS=("$@")
+
+for feed in "${FEEDS[@]}"
+do
+ concert=$(dirname "${feed}")/concerts.in
+
+ PYTHONPATH="${ROOT}" \
+ "${HERE}"/build-feed.py "${concert}" "${feed}" \
+ "${HERE}"/concerts-pubdates.json ${domain}
+done
diff --git a/admin/feeds/concerts-pubdates.json b/admin/feeds/concerts-pubdates.json
new file mode 100644
index 0000000..4232ed7
--- /dev/null
+++ b/admin/feeds/concerts-pubdates.json
@@ -0,0 +1,15 @@
+{
+ "2019-10-05T17:00": null,
+ "2019-10-06T16:00": null,
+ "2020-03-08T16:00": null,
+ "2020-08-24T20:00": null,
+ "2021-04-03T20:00": "2021-03-19T16:00",
+ "2021-06-13T15:00": "2021-03-19T16:00",
+ "2021-08-17T20:30": null,
+ "2021-08-19T20:00": null,
+ "2021-10-25T18:00": null,
+ "2021-10-28T18:00": null,
+ "2021-12-12T16:00": "2021-11-23T23:28",
+ "2021-12-31T20:00": null,
+ "2022-05-07T17:00": null
+}
diff --git a/build-feed.py b/build-feed.py
deleted file mode 100755
index 5fe5c04..0000000
--- a/build-feed.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/env python3
-
-from datetime import datetime
-import json
-import re
-from sys import argv
-from urllib.parse import urljoin
-
-from lxml.builder import E
-from lxml.etree import CDATA, XML, indent, tostring
-
-from helpers import (
- DATE_FORMATTERS,
- guess_language,
- read_concerts,
- tmplocale,
- touchup_plaintext,
-)
-
-
-# TODO: handle timezones correctly.
-# Places to disambiguate:
-#
-# - concerts.in:
-# either add the zone explicitly, or deduce it from the place,
-# assuming all times in concerts.in are local times.
-#
-# - concerts-pubdates.json:
-# just add the zone explicitly.
-#
-# Until then, assume all these "naive times" describe the same timezone
-# (CET/CEST).
-
-
-TIMEZONE = datetime.now().astimezone().tzinfo
-NOW = datetime.now(tz=TIMEZONE)
-DATE_FORMAT = '%-d %b %Y %H:%M %z'
-
-# TODO: add item pubDate
-
-
-LOCALIZED_TEXT = {
- 'en': {
- 'title': 'Bellefeuille Quartet',
- 'indexpath': 'en/',
- 'description': 'News from the Bellefeuille quartet',
- },
- 'fr': {
- 'title': 'Quatuor Bellefeuille',
- 'indexpath': '/',
- 'description': 'Des nouvelles du quatuor Bellefeuille',
- },
-}
-
-LOCALIZED_FORMATS = {
- 'en': {
- 'title': lambda c: f'{c.time.strftime("%B %-d %Y")} in {c.place}',
- },
- 'fr': {
- 'title': lambda c: f'{c.time.strftime("%-d %B %Y")} à {c.place}',
- },
-}
-
-
-def join(sequence, joiner_factory):
- # There's got to be a standard itertools/functools thingy to do that…
- result = []
-
- for i, item in enumerate(sequence, start=1):
- result.append(item)
-
- if i == len(sequence):
- return result
-
- result.append(joiner_factory())
-
-
-CDATA_INDENT = 8*' '
-
-
-def cdata_concert(concert, lang):
- formatters = DATE_FORMATTERS[lang]
-
- blocks = []
-
- if concert.warning is not None:
- blocks.append(E.p(concert.warning))
-
- with tmplocale(lang):
- blocks.extend((
- E.p(formatters['date'](concert.time)),
- E.p(formatters['time'](concert.time)),
- ))
-
- blocks.extend((
- E.p(*join(concert.address.splitlines(), E.br)),
- E.ol(
- *(XML(f'{touchup_plaintext(p)} ')
- for p in concert.pieces.splitlines())
- ),
- *(E.p(line) for line in concert.instructions.splitlines()),
- ))
-
- for b in blocks:
- indent(b)
-
- html_blocks = (tostring(b, encoding='utf-8').decode() for b in blocks)
-
- cdata = '\n' + '\n'.join(html_blocks) + '\n'
- cdata = re.sub('^', CDATA_INDENT, cdata, flags=re.MULTILINE)
-
- return CDATA(cdata)
-
-
-def generate_concert(concert, concerts_url, pubdates, lang):
- formatters = LOCALIZED_FORMATS[lang]
-
- with tmplocale(lang):
- title = formatters['title'](concert)
-
- anchor = f'concert-{concert.time.strftime("%F")}'
-
- item = E.item(
- E.title(title),
- E.link(f'{concerts_url}#{anchor}'),
- E.description(cdata_concert(concert, lang)),
- )
-
- pubdate_str = pubdates[concert.time.isoformat(timespec='minutes')]
-
- if pubdate_str is not None:
- pubdate = datetime.fromisoformat(pubdate_str).replace(tzinfo=TIMEZONE)
- item.append(E.pubDate(pubdate.strftime(DATE_FORMAT)))
-
- return item
-
-
-def generate_concerts(concerts_src, concerts_url, concerts_pubdates, lang):
- with open(concerts_pubdates) as pubdates_file:
- pubdates = json.load(pubdates_file)
-
- return tuple(
- generate_concert(c, concerts_url, pubdates, lang)
- for c in read_concerts(concerts_src)
- )
-
-
-def main(concerts_src, feed_dst, concerts_pubdates, domain):
- lang = guess_language(concerts_src)
- text = LOCALIZED_TEXT[lang]
-
- url = f'https://{domain}'
- index_url = urljoin(url, text['indexpath'])
- concerts_url = urljoin(index_url, 'concerts.html')
-
- now_formatted = NOW.strftime(DATE_FORMAT)
-
- concerts = generate_concerts(
- concerts_src, concerts_url, concerts_pubdates, lang
- )
-
- rss = E.rss(
- E.channel(
- E.title(text['title']),
- E.link(index_url),
- E.description(text['description']),
- E.image(
- E.url(urljoin(url, 'images/logo.svg')),
- E.link(concerts_url),
- ),
- E.lastBuildDate(now_formatted),
- E.pubDate(now_formatted),
- E.language(lang),
- *concerts,
- ),
- version='2.0',
- )
-
- indent(rss)
-
- with open(feed_dst, 'wb') as feed:
- feed.write(tostring(rss, encoding='utf-8', xml_declaration=True))
-
-
-if __name__ == '__main__':
- main(*argv[1:])
diff --git a/build-feed.sh b/build-feed.sh
deleted file mode 100755
index f537e96..0000000
--- a/build-feed.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# TODO: someday, generate both concerts page and feeds from a
-# plaintext list of concerts.
-
-set -eu
-
-input=$1
-output=$2
-
-. settings.sh
-
-sed s,'{DOMAIN}',"${domain}", "${input}" > "${output}"
diff --git a/concerts-pubdates.json b/concerts-pubdates.json
deleted file mode 100644
index 4232ed7..0000000
--- a/concerts-pubdates.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "2019-10-05T17:00": null,
- "2019-10-06T16:00": null,
- "2020-03-08T16:00": null,
- "2020-08-24T20:00": null,
- "2021-04-03T20:00": "2021-03-19T16:00",
- "2021-06-13T15:00": "2021-03-19T16:00",
- "2021-08-17T20:30": null,
- "2021-08-19T20:00": null,
- "2021-10-25T18:00": null,
- "2021-10-28T18:00": null,
- "2021-12-12T16:00": "2021-11-23T23:28",
- "2021-12-31T20:00": null,
- "2022-05-07T17:00": null
-}
--
cgit v1.2.3
From a7b877da001054378e86cb32bc8a9467423f7e5d Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Wed, 23 Feb 2022 10:37:11 +0100
Subject: Remove superfluous whitespace from feeds
---
admin/feeds/build-feed.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/admin/feeds/build-feed.py b/admin/feeds/build-feed.py
index 5fe5c04..e835ad7 100755
--- a/admin/feeds/build-feed.py
+++ b/admin/feeds/build-feed.py
@@ -75,9 +75,6 @@ def join(sequence, joiner_factory):
result.append(joiner_factory())
-CDATA_INDENT = 8*' '
-
-
def cdata_concert(concert, lang):
formatters = DATE_FORMATTERS[lang]
@@ -101,15 +98,17 @@ def cdata_concert(concert, lang):
*(E.p(line) for line in concert.instructions.splitlines()),
))
+ # Do a silly dance to indent CDATA correctly.
+
for b in blocks:
indent(b)
html_blocks = (tostring(b, encoding='utf-8').decode() for b in blocks)
- cdata = '\n' + '\n'.join(html_blocks) + '\n'
- cdata = re.sub('^', CDATA_INDENT, cdata, flags=re.MULTILINE)
+ cdata = '\n'.join(html_blocks) + '\n'
+ cdata = re.sub('^', 8*' ', cdata, flags=re.MULTILINE)
- return CDATA(cdata)
+ return CDATA('\n' + cdata)
def generate_concert(concert, concerts_url, pubdates, lang):
--
cgit v1.2.3
From cd1fde0ab2914ae44f1872927dbbe6fc19d63743 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Wed, 23 Feb 2022 10:37:35 +0100
Subject: Update feeds
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
🎉
---
en/feed.xml | 264 ++++++++++++++++++++++++++++++++++++++++++++----------------
feed.xml | 260 ++++++++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 392 insertions(+), 132 deletions(-)
diff --git a/en/feed.xml b/en/feed.xml
index a2557e7..02cdf81 100644
--- a/en/feed.xml
+++ b/en/feed.xml
@@ -1,87 +1,215 @@
-
+
Bellefeuille Quartet
- https://{DOMAIN}
+ https://quatuorbellefeuille.com/en/
News from the Bellefeuille quartet
- https://{DOMAIN}/images/logo.svg
- https://{DOMAIN}/en/concerts.html
+ https://quatuorbellefeuille.com/images/logo.svg
+ https://quatuorbellefeuille.com/en/concerts.html
+ 23 Feb 2022 10:27 +0100
+ 23 Feb 2022 10:27 +0100
en
-
-
December 12 2021 in Paris
- https://{DOMAIN}/en/concerts.html#concert-2021-12-12
+ October 5 2019 in Le Buisson de Cadouin
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2019-10-05
+ Saturday October 5, 2019
+ 05:00 pm
+ Pôle d'Animation Culturelle Avenue d'Aquitaine 24480 Le Buisson de Cadouin
+
+ Mozart quartet No. 17, KV. 458, “The Hunt”
+ Mendelssohn quartet No. 3, Op. 44 No. 1
+ Ravel string quartet
+
+ Information and reservation: https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+ ]]>
+
+ -
+
October 6 2019 in Lalinde
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2019-10-06
+ Sunday October 6, 2019
+ 04:00 pm
+ Espace Jacques Brel 1 rue salle des fêtes 24150 Lalinde
+
+ Beethoven quartet Op. 18 No. 4
+ Chostakovitch quartet No. 11
+ Ravel string quartet
+
+ Information and reservation: https://musiqueaucoeurdesbastides.jimdofree.com/
+ ]]>
+
+ -
+
March 8 2020 in Paris
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2020-03-08
+ Sunday March 8, 2020
+ 04:00 pm
+ Chapelle Saint-Louis de la Salpêtrière 47 boulevard de l'Hôpital 75013 Paris
+
+ Haydn quartet Op. 76 No. 1
+ Beethoven quartet No. 7, Op. 59 No. 1
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
August 24 2020 in Flaine
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2020-08-24
Sunday December 12, 2021
- 04:00 pm
-
- Chapelle Saint-Louis de la Salpêtrière
- 47 boulevard de l'Hôpital
- 75013 Paris
-
-
- Haydn 1st movement of quartet Op. 76 No. 1
- Schubert quartettsatz
- Beethoven quartet No. 7, Op. 59 No. 1
-
-
- Free admission without reservation, subject to the number of
- available places.
-
-
- For more information, please contact
- quatuorbellefeuille@gmail.com
-
- ]]>
- Tue, 23 Nov 2021 23:28:03 +0100
+ Monday August 24, 2020
+ 08:00 pm
+ Auditorium Éric & Sylvie Boissonnas Flaine Forêt Route de Flaine 74300 Arâches-la-Frasse
+
+ Beethoven string trio Op. 9 No. 3
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
-
April 3 2021 in Dinard
- https://{DOMAIN}/en/concerts.html#concert-2021-04-03
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-04-03
POSTPONED
- Saturday April 3, 2021
- 08:00 pm
- Dinard
-
- Haydn quartet Op. 76 No. 1
- Brahms quartet Op. 51 No. 2
- Ravel string quartet
-
-
- Information and reservation:
- https://weekenddemusiqueclassique.fr
-
- ]]>
- Fri, 19 Mar 2021 16:00:00 +0100
+ POSTPONED
+ Saturday April 3, 2021
+ 08:00 pm
+ Dinard
+
+ Haydn quartet Op. 76 No. 1
+ Brahms quartet Op. 51 No. 2
+ Ravel string quartet
+
+ Information and reservation: https://weekenddemusiqueclassique.fr
+ ]]>
+ 19 Mar 2021 16:00 +0100
-
June 13 2021 in Paris
- https://{DOMAIN}/en/concerts.html#concert-2021-06-13
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-06-13
+ CANCELED
+ Sunday June 13, 2021
+ 03:00 pm
+ Église Sainte-Claire d’Assise Place de la Porte-de-Pantin 75019 Paris
+
+ Haydn quartet Op. 76 No. 1
+ Beethoven quartet No. 7, Op. 59 No. 1
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
+ 19 Mar 2021 16:00 +0100
+
+ -
+
August 17 2021 in Flaine
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-08-17
+ Tuesday August 17, 2021
+ 08:30 pm
+ Église des Carroz Route de Flaine 74300 Les Carroz-d’Arâches
+
+ Ravel string quartet
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
August 19 2021 in Flaine
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-08-19
+ Thursday August 19, 2021
+ 08:00 pm
+ Auditorium Éric & Sylvie Boissonnas Flaine Forêt Route de Flaine 74300 Arâches-la-Frasse
+
+ Bartók quartet No. 2
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
October 25 2021 in Mello
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-10-25
+ Monday October 25, 2021
+ 06:00 pm
+ Le grand Mello Route de Creil 60660 Mello
+
+ Haydn quartet Op. 76 No. 1
+ Schubert quartettsatz
+ Brahms quartet Op. 51 No. 2
+
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+ ]]>
+
+ -
+
October 28 2021 in Paris
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-10-28
+ Thursday October 28, 2021
+ 06:00 pm
+ Casa Saint Germain des Prés 1 rue Madame 75006 Paris
+
+ Schubert quartettsatz
+ Brahms quartet Op. 51 No. 2
+ Ravel string quartet
+
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+ ]]>
+
+ -
+
December 12 2021 in Paris
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-12-12
+ Sunday December 12, 2021
+ 04:00 pm
+ Chapelle Saint-Louis de la Salpêtrière 47 boulevard de l'Hôpital 75013 Paris
+
+ Haydn 1st movement of quartet Op. 76 No. 1
+ Schubert quartettsatz
+ Beethoven quartet No. 7, Op. 59 No. 1
+
+ Free admission without reservation, subject to the number of available places.
+ For more information, please contact quatuorbellefeuille@gmail.com
+ ]]>
+ 23 Nov 2021 23:28 +0100
+
+ -
+
December 31 2021 in Dilbeek
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2021-12-31
+ Friday December 31, 2021
+ 08:00 pm
+ Château Grand-Bigard Isidoor van Beverenstraat 5 1702 Dilbeek Belgium
+
+ Haydn 1st movement of quartet Op. 76 No. 1
+ Schubert quartettsatz
+ Ravel string quaret
+
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+ ]]>
+
+ -
+
May 7 2022 in Saint-Domineuc
+ https://quatuorbellefeuille.com/en/concerts.html#concert-2022-05-07
CANCELED
- Sunday June 13, 2021
- 03:00 pm
-
- Église Sainte-Claire d’Assise
- Place de la Porte-de-Pantin
- 75019 Paris
-
-
- Haydn quartet Op. 76 No. 1
- Beethoven quartet No. 7, Op. 59 No. 1
-
-
- Free admission without reservation, subject to the number of
- available places.
-
-
- For more information, please contact
- quatuorbellefeuille@gmail.com
-
- ]]>
- Fri, 19 Mar 2021 16:00:00 +0100
+ Saturday May 7, 2022
+ 05:00 pm
+ Le Pianorium 4 rue du Stade 35190 Saint-Domineuc
+
+ Haydn 1st movement of quartet Op. 76 No. 1
+ Mendelssohn quartet No. 3, Op. 44 No. 1
+ Schubert quartettsatz
+ Shostakovich quartet
+
+ Free admission, subject to the number of available places.
+ Contact info@pianorium.fr to make a reservation.
+ ]]>
-
+
\ No newline at end of file
diff --git a/feed.xml b/feed.xml
index 3842285..2e69710 100644
--- a/feed.xml
+++ b/feed.xml
@@ -1,83 +1,215 @@
-
+
Quatuor Bellefeuille
- https://{DOMAIN}
+ https://quatuorbellefeuille.com/
Des nouvelles du quatuor Bellefeuille
- https://{DOMAIN}/images/logo.svg
- https://{DOMAIN}/concerts.html
+ https://quatuorbellefeuille.com/images/logo.svg
+ https://quatuorbellefeuille.com/concerts.html
+ 23 Feb 2022 10:27 +0100
+ 23 Feb 2022 10:27 +0100
fr
-
-
12 décembre 2021 à Paris
- https://{DOMAIN}/concerts.html#concert-2021-12-12
+ 5 octobre 2019 à Le Buisson de Cadouin
+ https://quatuorbellefeuille.com/concerts.html#concert-2019-10-05
+ Samedi 5 octobre 2019
+ 17h00
+ Pôle d'Animation Culturelle Avenue d'Aquitaine 24480 Le Buisson de Cadouin
+
+ Mozart quatuor n°17, KV. 458, « La Chasse »
+ Mendelssohn quatuor n°3, op.44 n°1
+ Ravel quatuor à cordes
+
+ Informations et réservations : https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+ ]]>
+
+ -
+
6 octobre 2019 à Lalinde
+ https://quatuorbellefeuille.com/concerts.html#concert-2019-10-06
+ Dimanche 6 octobre 2019
+ 16h00
+ Espace Jacques Brel 1 rue salle des fêtes 24150 Lalinde
+
+ Beethoven quatuor op.18 n°4
+ Chostakovitch quatuor n°11
+ Ravel quatuor à cordes
+
+ Informations et réservations : https://musiqueaucoeurdesbastides.jimdofree.com/
+ ]]>
+
+ -
+
8 mars 2020 à Paris
+ https://quatuorbellefeuille.com/concerts.html#concert-2020-03-08
+ Dimanche 8 mars 2020
+ 16h00
+ Chapelle Saint-Louis de la Salpêtrière 47 boulevard de l'Hôpital 75013 Paris
+
+ Haydn quatuor op.76 n°1
+ Beethoven quatuor n°7, op.59 n°1
+
+ Entrée libre sans réservation dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
24 août 2020 à Flaine
+ https://quatuorbellefeuille.com/concerts.html#concert-2020-08-24
Dimanche 12 décembre 2021
- 16h00
-
- Chapelle Saint-Louis de la Salpêtrière
- 47 boulevard de l'Hôpital
- 75013 Paris
-
-
- Haydn 1er mouvement du quatuor op.76 n°1
- Schubert quartettsatz
- Beethoven quatuor n°7, op.59 n°1
-
-
- Pour plus d'informations, merci de contacter :
- quatuorbellefeuille@gmail.com
-
- ]]>
- Tue, 23 Nov 2021 23:28:03 +0100
+ Lundi 24 août 2020
+ 20h00
+ Auditorium Éric & Sylvie Boissonnas Flaine Forêt Route de Flaine 74300 Arâches-la-Frasse
+
+ Beethoven trio à cordes op.9 n°3
+
+ Entrée libre sans réservation, dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
-
3 avril 2021 à Dinard
- https://{DOMAIN}/concerts.html#concert-2021-04-03
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-04-03
REPORTÉ
- Samedi 3 avril 2021
- 20h00
- Dinard
-
- Haydn quatuor op.76 n°1
- Brahms quatuor op.51 n°2
- Ravel quatuor à cordes
-
-
- Informations et réservations :
- https://weekenddemusiqueclassique.fr
-
- ]]>
- Fri, 19 Mar 2021 16:00:00 +0100
+ REPORTÉ
+ Samedi 3 avril 2021
+ 20h00
+ Dinard
+
+ Haydn quatuor op.76 n°1
+ Brahms quatuor op.51 n°2
+ Ravel quatuor à cordes
+
+ Informations et réservations : https://weekenddemusiqueclassique.fr
+ ]]>
+ 19 Mar 2021 16:00 +0100
-
13 juin 2021 à Paris
- https://{DOMAIN}/concerts.html#concert-2021-06-13
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-06-13
+ ANNULÉ
+ Dimanche 13 juin 2021
+ 15h00
+ Église Sainte-Claire d’Assise Place de la Porte-de-Pantin 75019 Paris
+
+ Haydn quatuor op.76 n°1
+ Beethoven quatuor n°7, op.59 n°1
+
+ Entrée libre sans réservation, dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
+ 19 Mar 2021 16:00 +0100
+
+ -
+
17 août 2021 à Flaine
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-08-17
+ Mardi 17 août 2021
+ 20h30
+ Église des Carroz Route de Flaine 74300 Les Carroz-d’Arâches
+
+ Ravel quatuor à cordes
+
+ Entrée libre sans réservation, dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
19 août 2021 à Flaine
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-08-19
+ Jeudi 19 août 2021
+ 20h00
+ Auditorium Éric & Sylvie Boissonnas Flaine Forêt Route de Flaine 74300 Arâches-la-Frasse
+
+ Bartók quatuor n°2
+
+ Entrée libre sans réservation, dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
+
+ -
+
25 octobre 2021 à Mello
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-10-25
+ Lundi 25 octobre 2021
+ 18h00
+ Le grand Mello Route de Creil 60660 Mello
+
+ Haydn quatuor op.76 n°1
+ Schubert quartettsatz
+ Brahms quatuor op.51 n°2
+
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+ ]]>
+
+ -
+
28 octobre 2021 à Paris
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-10-28
+ Jeudi 28 octobre 2021
+ 18h00
+ Casa Saint Germain des Prés 1 rue Madame 75006 Paris
+
+ Schubert quartettsatz
+ Brahms quatuor op.51 n°2
+ Ravel quatuor à cordes
+
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+ ]]>
+
+ -
+
12 décembre 2021 à Paris
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-12-12
+ Dimanche 12 décembre 2021
+ 16h00
+ Chapelle Saint-Louis de la Salpêtrière 47 boulevard de l'Hôpital 75013 Paris
+
+ Haydn 1er mouvement du quatuor op.76 n°1
+ Schubert quartettsatz
+ Beethoven quatuor n°7, op.59 n°1
+
+ Entrée libre sans réservation dans la limite des places disponibles.
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ ]]>
+ 23 Nov 2021 23:28 +0100
+
+ -
+
31 décembre 2021 à Dilbeek
+ https://quatuorbellefeuille.com/concerts.html#concert-2021-12-31
+ Vendredi 31 décembre 2021
+ 20h00
+ Château Grand-Bigard Isidoor van Beverenstraat 5 1702 Dilbeek Belgique
+
+ Haydn 1er mouvement du quatuor op.76 n°1
+ Schubert quartettsatz
+ Ravel quatuor à cordes
+
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+ ]]>
+
+ -
+
7 mai 2022 à Saint-Domineuc
+ https://quatuorbellefeuille.com/concerts.html#concert-2022-05-07
ANNULÉ
- Dimanche 13 juin 2021
- 15h00
-
- Église Sainte-Claire d’Assise
- Place de la Porte-de-Pantin
- 75019 Paris
-
-
- Haydn quatuor op.76 n°1
- Beethoven quatuor n°7, op.59 n°1
-
-
- Entrée libre sans réservation, dans la limite des places
- disponibles.
-
-
- Pour plus d'informations, merci de contacter :
- quatuorbellefeuille@gmail.com
-
- ]]>
- Fri, 19 Mar 2021 16:00:00 +0100
+ Samedi 7 mai 2022
+ 17h00
+ Le Pianorium 4 rue du Stade 35190 Saint-Domineuc
+
+ Haydn 1er mouvement du quatuor op.76 n°1
+ Mendelssohn quatuor n°3, op.44 n°1
+ Schubert quartettsatz
+ Chostakovitch quatuor
+
+ Entrée libre dans la limite des places disponibles.
+ Réservation possible à l'adresse suivante : info@pianorium.fr
+ ]]>
-
+
\ No newline at end of file
--
cgit v1.2.3
From a3b76e82d935d78e41aa54c3228dbd6fb9e36fc1 Mon Sep 17 00:00:00 2001
From: Kévin Le Gouguec
Date: Wed, 23 Feb 2022 20:29:50 +0100
Subject: Fix instructions HTMLization & tidy up
Thank Humanity for linters.
---
Makefile | 2 +-
admin/feeds/build-feed.py | 12 ++++++++----
build-concerts.py | 15 ++++++++-------
en/feed.xml | 42 +++++++++++++++++++++++++++---------------
feed.xml | 43 ++++++++++++++++++++++++++++---------------
helpers.py | 2 ++
6 files changed, 74 insertions(+), 42 deletions(-)
diff --git a/Makefile b/Makefile
index 055daf8..ca01374 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ scripts_folders = $(call dirnames,$(scripts))
all: site
-feeds: $(feeds_folders)
+feeds:
./admin/feeds/build-feeds.sh $(feeds_src)
upload: site
diff --git a/admin/feeds/build-feed.py b/admin/feeds/build-feed.py
index e835ad7..e010b63 100755
--- a/admin/feeds/build-feed.py
+++ b/admin/feeds/build-feed.py
@@ -70,10 +70,12 @@ def join(sequence, joiner_factory):
result.append(item)
if i == len(sequence):
- return result
+ break
result.append(joiner_factory())
+ return result
+
def cdata_concert(concert, lang):
formatters = DATE_FORMATTERS[lang]
@@ -89,13 +91,15 @@ def cdata_concert(concert, lang):
E.p(formatters['time'](concert.time)),
))
+ pieces = touchup_plaintext(concert.pieces)
+ instructions = touchup_plaintext(concert.instructions)
+
blocks.extend((
E.p(*join(concert.address.splitlines(), E.br)),
E.ol(
- *(XML(f'{touchup_plaintext(p)} ')
- for p in concert.pieces.splitlines())
+ *(XML(f'{line} ') for line in pieces.splitlines())
),
- *(E.p(line) for line in concert.instructions.splitlines()),
+ *(XML(f'{line}
') for line in instructions.splitlines()),
))
# Do a silly dance to indent CDATA correctly.
diff --git a/build-concerts.py b/build-concerts.py
index 4f55f12..6e99673 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -2,7 +2,6 @@
from datetime import datetime
from pathlib import Path
-import re
from sys import argv
from helpers import (
@@ -71,17 +70,19 @@ THUMBNAIL_TEMPLATE = '''\
def format_credits(illustration):
- credits = illustration.source_name
+ attribution = illustration.source_name
if illustration.source_link is not None:
- credits = (f''
- f'{illustration.source_name}'
- ' ')
+ attribution = (
+ f''
+ f'{illustration.source_name}'
+ ' '
+ )
if illustration.license_info is not None:
- credits += ' / ' + illustration.license_info.format()
+ attribution += ' / ' + illustration.license_info.format()
- return credits
+ return attribution
def format_thumbnail(concert, imgdir, lang):
diff --git a/en/feed.xml b/en/feed.xml
index 02cdf81..72d5c8e 100644
--- a/en/feed.xml
+++ b/en/feed.xml
@@ -8,8 +8,8 @@
https://quatuorbellefeuille.com/images/logo.svg
https://quatuorbellefeuille.com/en/concerts.html
- 23 Feb 2022 10:27 +0100
- 23 Feb 2022 10:27 +0100
+ 23 Feb 2022 20:28 +0100
+ 23 Feb 2022 20:28 +0100
en
-
October 5 2019 in Le Buisson de Cadouin
@@ -23,7 +23,8 @@
Mendelssohn quartet No. 3, Op. 44 No. 1
Ravel string quartet
- Information and reservation: https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+ Information and reservation: https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+
]]>
-
@@ -38,7 +39,8 @@
Chostakovitch quartet No. 11
Ravel string quartet
- Information and reservation: https://musiqueaucoeurdesbastides.jimdofree.com/
+ Information and reservation: https://musiqueaucoeurdesbastides.jimdofree.com/
+
]]>
-
@@ -53,7 +55,8 @@
Beethoven quartet No. 7, Op. 59 No. 1
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
-
@@ -67,7 +70,8 @@
Beethoven string trio Op. 9 No. 3
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
-
@@ -83,7 +87,8 @@
Brahms quartet Op. 51 No. 2
Ravel string quartet
- Information and reservation: https://weekenddemusiqueclassique.fr
+ Information and reservation: https://weekenddemusiqueclassique.fr
+
]]>
19 Mar 2021 16:00 +0100
@@ -100,7 +105,8 @@
Beethoven quartet No. 7, Op. 59 No. 1
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
19 Mar 2021 16:00 +0100
@@ -115,7 +121,8 @@
Ravel string quartet
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
-
@@ -129,7 +136,8 @@
Bartók quartet No. 2
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
-
@@ -144,7 +152,8 @@
Schubert quartettsatz
Brahms quartet Op. 51 No. 2
- For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+
]]>
-
@@ -159,7 +168,8 @@
Brahms quartet Op. 51 No. 2
Ravel string quartet
- For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+
]]>
-
@@ -175,7 +185,8 @@
Beethoven quartet No. 7, Op. 59 No. 1
Free admission without reservation, subject to the number of available places.
- For more information, please contact quatuorbellefeuille@gmail.com
+ For more information, please contact quatuorbellefeuille@gmail.com
+
]]>
23 Nov 2021 23:28 +0100
@@ -191,7 +202,8 @@
Schubert quartettsatz
Ravel string quaret
- For more information, please refer to: https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+ For more information, please refer to: https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+
]]>
-
@@ -208,7 +220,7 @@
Shostakovich quartet
Free admission, subject to the number of available places.
- Contact info@pianorium.fr to make a reservation.
+ Contact info@pianorium.fr to make a reservation.
]]>
diff --git a/feed.xml b/feed.xml
index 2e69710..026e284 100644
--- a/feed.xml
+++ b/feed.xml
@@ -8,8 +8,8 @@
https://quatuorbellefeuille.com/images/logo.svg
https://quatuorbellefeuille.com/concerts.html
- 23 Feb 2022 10:27 +0100
- 23 Feb 2022 10:27 +0100
+ 23 Feb 2022 20:27 +0100
+ 23 Feb 2022 20:27 +0100
fr
-
5 octobre 2019 à Le Buisson de Cadouin
@@ -23,7 +23,8 @@
Mendelssohn quatuor n°3, op.44 n°1
Ravel quatuor à cordes
- Informations et réservations : https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+ Informations et réservations : https://arcadesinfo.com/évènement/quatuor-a-cordes-bellefeuille/
+
]]>
-
@@ -38,7 +39,8 @@
Chostakovitch quatuor n°11
Ravel quatuor à cordes
- Informations et réservations : https://musiqueaucoeurdesbastides.jimdofree.com/
+ Informations et réservations : https://musiqueaucoeurdesbastides.jimdofree.com/
+
]]>
-
@@ -53,7 +55,8 @@
Beethoven quatuor n°7, op.59 n°1
Entrée libre sans réservation dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
-
@@ -67,7 +70,8 @@
Beethoven trio à cordes op.9 n°3
Entrée libre sans réservation, dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
-
@@ -83,7 +87,8 @@
Brahms quatuor op.51 n°2
Ravel quatuor à cordes
- Informations et réservations : https://weekenddemusiqueclassique.fr
+ Informations et réservations : https://weekenddemusiqueclassique.fr
+
]]>
19 Mar 2021 16:00 +0100
@@ -100,7 +105,8 @@
Beethoven quatuor n°7, op.59 n°1
Entrée libre sans réservation, dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
19 Mar 2021 16:00 +0100
@@ -115,7 +121,8 @@
Ravel quatuor à cordes
Entrée libre sans réservation, dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
-
@@ -129,7 +136,8 @@
Bartók quatuor n°2
Entrée libre sans réservation, dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
-
@@ -144,7 +152,8 @@
Schubert quartettsatz
Brahms quatuor op.51 n°2
- Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-25-2021-le-grand-mello-mello-france/
+
]]>
-
@@ -159,7 +168,8 @@
Brahms quatuor op.51 n°2
Ravel quatuor à cordes
- Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/october-28-2021-casa-st-germain-des-pres-paris/
+
]]>
-
@@ -175,7 +185,8 @@
Beethoven quatuor n°7, op.59 n°1
Entrée libre sans réservation dans la limite des places disponibles.
- Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+ Pour plus d'informations, merci de contacter : quatuorbellefeuille@gmail.com
+
]]>
23 Nov 2021 23:28 +0100
@@ -191,7 +202,8 @@
Schubert quartettsatz
Ravel quatuor à cordes
- Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+ Pour plus d'informations, rendez-vous sur : https://www.ledimoredelquartetto.eu/en/december-31-2021-grand-bigard-castle-brussels-belgium/
+
]]>
-
@@ -208,7 +220,8 @@
Chostakovitch quatuor
Entrée libre dans la limite des places disponibles.
- Réservation possible à l'adresse suivante : info@pianorium.fr
+ Réservation possible à l'adresse suivante : info@pianorium.fr
+
]]>
diff --git a/helpers.py b/helpers.py
index a6c4de2..11a13ca 100644
--- a/helpers.py
+++ b/helpers.py
@@ -43,6 +43,7 @@ _LICENSE_RE = re.compile(
'('+'|'.join(_LICENSE_URLS.keys())+')' + ' ([0-9.]+)'
)
+
@dataclass
class LicenseInfo:
tag: str
@@ -103,6 +104,7 @@ class Concert:
def _optional(line):
return f'(?:{line})?'
+
_CONCERT_LINES = (
r'QUAND : (?P[^\n]+)\n',
r'O[UÙ] : (?P[^\n]+)\n',
--
cgit v1.2.3