From fc88b7f550316ebfeeaefa03e0aa211c9fdab16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=BCller?= Date: Wed, 23 Sep 2026 23:00:57 +0200 Subject: [PATCH 1/9] =?UTF-8?q?=E2=9E=95=EF=B8=8F=20Add=20plain=20text=20c?= =?UTF-8?q?ontent=20utilityfor=20songs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index fd0a1e1..28db887 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -316,6 +316,38 @@ function parsedContent(content: string, keyOffset: number, showChords: boolean, } }; +// build plain text content for a song's songsheet: header (title [key]), lyrics with chord lines optionally +// stripped and verse markers numbered/stripped, and an authors/copyright footer +const songPlainTextContent = (song: SongEntity, tuning: string, showChords: boolean): string => { + // add header + var content = song.title + ' [' + tuning + ']' + '\n\n'; + var lines = song.content.split('\n'); + // process lines + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + // handle chord line + if (!showChords && isChordLine(line)) continue; + // handle verse marker indentation + if (line.trim().toLowerCase().indexOf('--v') >= 0 && !isNaN(parseInt(line.trim().charAt(3)))) { + // if next line is chord line, prepend number to the line after + if (isChordLine(lines[i+1])) { + lines[i+2] = line.trim().charAt(3) + '. ' + lines[i+2]; + // add 3 spaces to next line to sync chords with text again + lines[i+1] = ' ' + lines[i+1]; + } else { + lines[i+1] = line.trim().charAt(3) + '. ' + lines[i+1]; + } + } + // handle marker + if (line.trim().indexOf('--') >= 0) continue; + // keep line for export + content += line + '\n'; + } + content += '\n' + song.authors?.join(', ') + '\n\n' + + '© ' + (song.year ? song.year + ' ' : '') + song.publisher.replace(/(?:\r\n|\r|\n)/g, '; '); + return content; +}; + // file download const download = (data: string | Blob, filename: string, isBlob = false): void => { var a = document.createElement('a'); @@ -524,6 +556,7 @@ export { bufferAndDefer, maximizePresentFontsize, parsedContent, + songPlainTextContent, download, humanDate, humanFileSize, From dd66a750f39df3b4b48a78219bbc19340fa3a356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=BCller?= Date: Wed, 23 Sep 2026 23:03:27 +0200 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=94=A8=20Use=20new=20utility=20for=20?= =?UTF-8?q?song=20txt=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/SongShow.vue | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/frontend/src/views/SongShow.vue b/frontend/src/views/SongShow.vue index b26e7ca..6311624 100644 --- a/frontend/src/views/SongShow.vue +++ b/frontend/src/views/SongShow.vue @@ -276,7 +276,7 @@