Skip to content

Commit

Permalink
[WIP] utilisation de plastex pour afficher les chants
Browse files Browse the repository at this point in the history
  • Loading branch information
Luthaf committed Jun 15, 2014
1 parent 0344bff commit c8d8013
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 53 deletions.
78 changes: 28 additions & 50 deletions generator/songs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from django.utils.encoding import smart_text
from django.conf.global_settings import LANGUAGES

from songbook_core.plastex import parsetex
from songbook_core.plastex import parsetex, SongParser

from generator.models import Song, Artist

Expand All @@ -30,55 +30,33 @@
import sys
import pprint

_BLOCKS_PATTERNS = [(r"\beginverse", '<p class="verse" >'),
(r"\begin{verse}", '<p class="verse" >'),
(r"\beginverse*", '<p class="verse_star" >'),
(r"\begin{verse*}", '<p class="verse_star" >'),
(r"\beginchorus", '<p class="chorus" >'),
(r"\begin{chorus}", '<p class="chorus" >'),
]

_BLOCKS_PATTERNS += [(r"\endverse", '</p>'),
(r"\end{verse}", '</p>'),
(r"\end{verse*}", '</p>'),
(r"\end{chorus}", '</p>'),
]


def parse_chords(content):
content = re.sub('\\\\\\[(.*?)\]({[^\\\\\s\n]*}|[^\\\\\s\n]*)',
'<span class="chord"><span class="chord-name">\g<1></span>'
'<span class="chord-text">\g<2></span></span>',
content)
content = content.replace('&', "♭")
content = content.replace('#', "♯&nbsp")
return content


def parse_blocks(content):
for TeX, HTML in _BLOCKS_PATTERNS:
content = content.replace(TeX, HTML)
return content


def parse_unsuported(content):
# remove the beggining of the song
content = re.sub('^(.*?)<p', '<p', content, flags=re.DOTALL)

# remove all other commands
content = re.sub(r'\\(\w*)[(.*)]{(.*)}', '', content)
content = re.sub(r'\\(\w*){(.*)}', '', content)
content = re.sub(r'\\(\w*)', '', content)

content = re.sub(r'{|}', '', content)
return content


def parse_song(content):
content = parse_blocks(content)
content = parse_chords(content)
content = parse_unsuported(content)
return content
def parse_song(filename):
tex = SongParser.parse(filename)
in_song = False
res = ""

for node in tex.allChildNodes:
if node.nodeName in ["chorus", "verse", "verse*", "bridge"]:
if not in_song:
in_song = True
part_name = node.nodeName
part_name.replace("*", "_star")
res += '<p class="{node}">\n'.format(node=node.nodeName)
elif node.nodeName == "par" and in_song:
res += '\n</p>\n'
elif node.nodeName == "chord" and in_song:
res += '<span class="chord"><span class="chord-name">'
for subnode in node.allChildNodes:
res += subnode
res += '</span><span class="chord-text">'
# TODO: get chord text
res += '</span></span>'
# TODO: advance in the loop
elif node.nodeName == "#text" and in_song:
res += node
res = res.replace('&', "♭")
res = res.replace('#', "♯&nbsp")

This comment has been minimized.

Copy link
@paternal

paternal Jun 16, 2014

Contributor

Pour info, j'ai des problèmes d'encodage de caractères ici : j'ai du modifier ces caractères pour pouvoir lancer le serveur.

This comment has been minimized.

Copy link
@Luthaf

Luthaf Jun 17, 2014

Author Contributor

Avec le bemol ? Normalement le diese ne devrait pas poser de problème pour les transmissions HTML.

Edit: on peut le remplacer par &#9837;

This comment has been minimized.

Copy link
@paternal

paternal Jun 17, 2014

Contributor
Traceback:
File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response  112.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python2.7/dist-packages/django/db/transaction.py" in inner
  371.                 return func(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/django/views/generic/base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/django/views/generic/base.py" in dispatch
  87.         return handler(request, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/django/views/generic/detail.py" in get
  111.         context = self.get_context_data(object=self.object)
File "/home/louis/projets/songbook/web/generator/views/songs.py" in get_context_data
  78.         context['content'] = _read_song(context['song'])
File "/home/louis/projets/songbook/web/generator/views/songs.py" in _read_song
  63.     return parse_song(path)
File "/home/louis/projets/songbook/web/generator/songs.py" in parse_song
  57.     res = res.replace('&', "♭")

Exception Type: UnicodeDecodeError at /fr/songs/traditionnel/vent-frais/
Exception Value: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

Et une erreur similaire pour le dièse. J'ai du les remplacer par &#9839; (dièse) et &#9837; (bémol) pour que l'erreur ne survienne pas.

Tant qu'on y est, en plaçant ces deux lignes à cet endroit là, on recherche ces caractères dans toute la chanson, alors qu'on ne veut les remplacer que dans les accords. C'est peut-être pertinent de les remonter quelques lignes plus haut, par exemple (à partir de cette version) :

iff --git a/generator/songs.py b/generator/songs.py
index 3cdb221..dcf7fce 100644
--- a/generator/songs.py
+++ b/generator/songs.py
@@ -46,15 +46,13 @@ def parse_song(filename):
             res += '\n</p>\n'
         elif node.nodeName == "chord" and in_song:
             res += '<span class="chord"><span class="chord-name">'
-            res += node.chord
+            res += node.chord.replace('&', "&#9837;").replace('#', "&#9839;&nbsp")
             res += '</span><span class="chord-text">'
             # TODO: get chord text
             res += '</span></span>'
             # TODO: advance in the loop
         elif node.nodeName == "#text" and in_song:
             res += node
-    res = res.replace('&', "♭")
-    res = res.replace('#', "♯&nbsp")
     return res

 # TODO: Write all the output to a log file

Je ne sais pas ce qui est le plus rapide : un replace() sur une grosse chaîne (toute la chanson), ou plein de replace() sur chacun des accords.
En plus, faire ce changement permettra de ne pas remplacer des & et # ailleurs dans la chanson, si jamais ils apparaissent dans la chanson.

This comment has been minimized.

Copy link
@Luthaf

Luthaf Jun 17, 2014

Author Contributor

Je ne sais pas ce qui est le plus rapide : un replace() sur une grosse chaîne (toute la chanson), ou plein de replace() sur chacun des accords.

Je ne sais pas non plus, mais les performances semblait bonne avec un replace global. Au passage le chaînage des remplace ne plante pas ? Parce que l'on met de caractères # a la place des &, puis on remplace les # par autre chose ...

En plus, faire ce changement permettra de ne pas remplacer des & et # ailleurs dans la chanson, si jamais ils apparaissent dans la chanson.

Il ne sont pas sensé apparaître ailleurs dans le fichier .sg, ce sont des caractères spéciaux TeX. Ils sont nécessairement dans des environnements \[], mais pas forcement dans des verse ou chorus. Mais on peut se passer de l'affichage de l'intro je pense.

This comment has been minimized.

Copy link
@paternal

paternal Jun 17, 2014

Contributor

Au passage le chaînage des remplace ne plante pas ? Parce que l'on met de caractères # a la place des &, puis on remplace les # par autre chose ...

Bien vu. Au final, remplacer "♭" et "♯" par u"♭" et u"♯" fonctionne pour moi. Deux petites questions :

  • est-ce qu'il ne manque pas un ; après le ♯&nbsp ?
  • pourquoi ajouter une espace insécable après dièse, mais pas après bémol ?

Il ne sont pas sensé apparaître ailleurs dans le fichier .sg, ce sont des caractères spéciaux TeX. [...]

Ils peuvent, si l'utilisateur les échappe (\& et \#). En particulier, je vois bien \& apparaitre dans le nom d'un groupe.

This comment has been minimized.

Copy link
@Luthaf

Luthaf Jun 17, 2014

Author Contributor

est-ce qu'il ne manque pas un ; après le ♯&nbsp ?
pourquoi ajouter une espace insécable après dièse, mais pas après bémol ?

Je n'y ai pas vraiment réfléchi, j'ai copie la première implémentation en JS par @oliverpool.

Ils peuvent, si l'utilisateur les échappe (& et #). En particulier, je vois bien & apparaitre dans le nom d'un groupe.

Pas faux ... mais les noms des groupes ne sont pas utilises lors de l'affichage. Il va falloir trouver une manière de faire pour gérer tout ca.

This comment has been minimized.

Copy link
@paternal

paternal Jun 17, 2014

Contributor

Mes recherches m'ont mené à ça : #77.

return res

# TODO: Write all the output to a log file
def import_song(repo, filepath):
Expand Down
4 changes: 1 addition & 3 deletions generator/views/songs.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ def get_context_data(self, **kwargs):

def _read_song(song):
path = os.path.join(SONGS_LIBRARY_DIR, 'songs', song.file_path)
with open(path, 'r') as song_file:
content = song_file.read()
return parse_song(content)
return parse_song(path)


class SongView(CurrentSongbookMixin, DetailView):
Expand Down

5 comments on commit c8d8013

@paternal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour le rendu, tu as regardé du côté des renderers, plutôt que de tout refaire à la main ?

@Luthaf
Copy link
Contributor Author

@Luthaf Luthaf commented on c8d8013 Jun 17, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui, mais les renderers ne semblait pas pratique a intégrer dans le processus de rendu des templates Django, sauf a écrire des fichiers temporaires.

@paternal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@paternal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui, mais les renderers ne semblait pas pratique a intégrer dans le processus de rendu des templates Django, sauf a écrire des fichiers temporaires.

J'ai l'impression qu'avec ce système, vous vous limitez à rendre uniquement les caractères, et interdisez les commandes LaTeX (à moins de faire un cas spécifique pour chaque commande gérée). Ça n'est pas mauvais en soi (ça ne me gêne pas qu'on limite à des caractères ce qui peut être inclus dans une chanson), mais c'est bien d'en être conscient.

@Luthaf
Copy link
Contributor Author

@Luthaf Luthaf commented on c8d8013 Jun 17, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

J'ai l'impression qu'avec ce système, vous vous limitez à rendre uniquement les caractères, et interdisez les commandes LaTeX

Tu as un exemple ? On ignore en effet les commandes comme \emph et compagnie, mais plasTeX est la pour nous permettre d’accéder au texte, non ?

Please sign in to comment.