Browse Source

Added plugin 'sorted'

pull/47/head
Louis 11 years ago
parent
commit
0a4d7638a0
  1. 18
      songbook_core/content/__init__.py
  2. 8
      songbook_core/content/section.py
  3. 25
      songbook_core/content/song.py
  4. 6
      songbook_core/content/songsection.py
  5. 23
      songbook_core/content/sorted.TODO
  6. 36
      songbook_core/content/sorted.py

18
songbook_core/content/__init__.py

@ -6,6 +6,7 @@ import importlib
import jinja2
import logging
import os
import re
from songbook_core.errors import SongbookError
@ -101,6 +102,7 @@ def render_content(context, content):
def process_content(content, config = None):
contentlist = []
plugins = load_plugins()
keyword_re = re.compile(r'^ *(?P<keyword>\w*) *(\((?P<argument>.*)\))? *$')
if not content:
content = [["song"]]
for elem in content:
@ -108,7 +110,17 @@ def process_content(content, config = None):
elem = ["song", elem]
if len(content) == 0:
content = ["song"]
if elem[0] not in plugins:
raise ContentError(elem[0], "Unknown content type.")
contentlist.extend(plugins[elem[0]](elem[0], config, *elem[1:]))
try:
match = keyword_re.match(elem[0]).groupdict()
except AttributeError:
raise ContentError(elem[0], "Cannot parse content type.")
(keyword, argument) = (match['keyword'], match['argument'])
if keyword not in plugins:
raise ContentError(keyword, "Unknown content type.")
contentlist.extend(plugins[keyword](
keyword,
argument = argument,
contentlist = elem[1:],
config = config,
))
return contentlist

8
songbook_core/content/section.py

@ -26,12 +26,12 @@ class Section(Content):
else:
return r'\{}[{}]{{{}}}'.format(self.keyword, self.short, self.name)
def parse(keyword, config, *arguments):
if (keyword not in KEYWORDS) and (len(arguments) != 1):
def parse(keyword, argument, contentlist, config):
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(keyword, "Starred section names must have exactly one argument.")
if (len(arguments) not in [1, 2]):
if (len(contentlist) not in [1, 2]):
raise ContentError(keyword, "Section can have one or two arguments.")
return [Section(keyword, *arguments)]
return [Section(keyword, *contentlist)]
CONTENT_PLUGINS = dict([(keyword, parse) for keyword in FULL_KEYWORDS])

25
songbook_core/content/song.py

@ -6,7 +6,7 @@ import jinja2
import logging
import os
from songbook_core.content import Content
from songbook_core.content import Content, process_content, ContentError
from songbook_core.files import recursive_find
from songbook_core.songs import Song
@ -33,12 +33,12 @@ class SongRenderer(Content, Song):
path = os.path.abspath(self.path)
return r'\input{{{}}}'.format(path)
def parse(keyword, config, *arguments):
def parse(keyword, argument, contentlist, config):
if 'languages' not in config:
config['languages'] = set()
songlist = []
if not arguments:
arguments = [
if not contentlist:
contentlist = [
os.path.relpath(
filename,
os.path.join(config['datadir'][0], 'songs'),
@ -49,7 +49,7 @@ def parse(keyword, config, *arguments):
"*.sg"
)
]
for elem in arguments:
for elem in contentlist:
before = len(songlist)
for songdir in [os.path.join(d, 'songs') for d in config['datadir']]:
for filename in glob.iglob(os.path.join(songdir, elem)):
@ -68,3 +68,18 @@ def parse(keyword, config, *arguments):
CONTENT_PLUGINS = {'song': parse}
class OnlySongsError(ContentError):
def __init__(self, not_songs):
self.not_songs = not_songs
def __str__(self):
return "Only songs are allowed, and the following items are not:" + str(not_songs)
def process_songs(content, config = None):
contentlist = process_content(content, config)
not_songs = [item for item in contentlist if not isinstance(item, SongRenderer)]
if not_songs:
raise OnlySongsError(not_songs)
return contentlist

6
songbook_core/content/songsection.py

@ -16,10 +16,10 @@ class SongSection(Content):
def render(self, __context):
return r'\{}{{{}}}'.format(self.keyword, self.name)
def parse(keyword, config, *arguments):
if (keyword not in KEYWORDS) and (len(arguments) != 1):
def parse(keyword, argument, contentlist, config):
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(keyword, "Starred section names must have exactly one argument.")
return [SongSection(keyword, *arguments)]
return [SongSection(keyword, *contentlist)]
CONTENT_PLUGINS = dict([(keyword, parse) for keyword in KEYWORDS])

23
songbook_core/content/sorted.TODO

@ -1,23 +0,0 @@
def __cmp__(self, other):
if not isinstance(other, Song):
return NotImplemented
for key in self.sort:
if key == "@title":
self_key = self.normalized_titles
other_key = other.normalized_titles
elif key == "@path":
self_key = locale.strxfrm(self.path)
other_key = locale.strxfrm(other.path)
elif key == "by":
self_key = self.normalized_authors
other_key = other.normalized_authors
else:
self_key = locale.strxfrm(self.args.get(key, ""))
other_key = locale.strxfrm(other.args.get(key, ""))
if self_key < other_key:
return -1
elif self_key > other_key:
return 1
return 0

36
songbook_core/content/sorted.py

@ -0,0 +1,36 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import locale
from songbook_core.content.song import OnlySongsError, process_songs
DEFAULT_SORT = ['by', 'album', '@title']
def key_generator(sort):
def ordered_song_keys(song):
songkey = []
for key in sort:
if key == "@title":
songkey.append(song.normalized_titles)
elif key == "@path":
songkey.append(locale.strxfrm(song.path))
elif key == "by":
songkey.append(song.normalized_authors)
else:
songkey.append(locale.strxfrm(song.args.get(key, "")))
return songkey
return ordered_song_keys
def parse(keyword, config, argument, contentlist):
if argument:
sort = [key.strip() for key in argument.split(",")]
else:
sort = DEFAULT_SORT
try:
songlist = process_songs(contentlist, config)
except OnlySongsError as error:
raise ContentError(keyword, "Content list of this keyword can bo only songs (or content that result into songs), and the following are not:" + str(error.not_songs))
return sorted(songlist, key=key_generator(sort))
CONTENT_PLUGINS = {'sorted': parse}
Loading…
Cancel
Save