Refactor lyric storage so each song owns its sections instead of sharing global labels. Adds song_sections (per song+label) owning song_slides; labels stay global ProPresenter group tags (name/color/macro). Arrangements now reference sections, so editing/importing one song no longer corrupts others that share a label name. - New: song_sections table + migration with safe backfill; SongSection, SongArrangementSection models; SongSectionController (edit/add/delete sections, immediate persistence) wired into SongEditModal. - Refactor writers/readers: CcliImport, ProImport, SongService, ArrangementController, SongController, ProExport, PDF, Translation (translation reset now section-scoped), CCLI pairing. - CCLI import fixes: parse SongSelect copy-icon format (German "Vers" abbrev + trailing author), fill empty CTS-synced songs instead of blocking as duplicate, distinct label colors per section kind, import&edit/existing-song open the edit modal (no 404/405), teleport paste dialog above assign dialog, preview shows section content, correct SongSelect search URL, copy-icon instructions. - Bookmarklet clicks #generalCopyLyricsButton and captures clipboard; serves correct host from request. - Export: embed key-visual/background under fixed bundle-relative names. - Tests updated for the section model; new section + isolation coverage.
75 lines
2.4 KiB
PHP
75 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\Config;
|
|
|
|
final class BookmarkletController extends Controller
|
|
{
|
|
public function show(Request $request): Response
|
|
{
|
|
$appUrl = rtrim($request->getSchemeAndHttpHost(), '/');
|
|
|
|
if ($appUrl === '') {
|
|
$appUrl = rtrim((string) Config::get('app.url', ''), '/');
|
|
}
|
|
|
|
$bookmarkletScript = <<<'BOOKMARKLET'
|
|
(function(){
|
|
var APP_URL = '__APP_URL__';
|
|
if(!location.hostname.includes('songselect.ccli.com')){
|
|
alert('Bitte öffne dieses Lesezeichen auf einer SongSelect Liedseite (songselect.ccli.com).');
|
|
return;
|
|
}
|
|
function send(text){
|
|
var ccliMatch = (text || '').match(/CCLI[\s#-]*(\d+)/i);
|
|
var payload = {
|
|
title: '',
|
|
author: '',
|
|
ccliId: ccliMatch ? ccliMatch[1] : '',
|
|
sourceUrl: location.href,
|
|
rawText: text || ''
|
|
};
|
|
var encoded = btoa(unescape(encodeURIComponent(JSON.stringify(payload))));
|
|
window.open(APP_URL + '/songs/import-from-ccli-paste?prefill=' + encoded, '_blank');
|
|
}
|
|
var btn = document.querySelector('#generalCopyLyricsButton');
|
|
if(!btn){
|
|
alert('Kopier-Symbol nicht gefunden. Bitte öffne die Liedtext-Ansicht auf SongSelect und versuche es erneut.');
|
|
return;
|
|
}
|
|
var captured = null;
|
|
function onCopy(e){
|
|
try { captured = e.clipboardData.getData('text/plain'); } catch(err) {}
|
|
}
|
|
document.addEventListener('copy', onCopy, true);
|
|
btn.click();
|
|
setTimeout(function(){
|
|
document.removeEventListener('copy', onCopy, true);
|
|
if(captured && captured.trim()){
|
|
send(captured);
|
|
return;
|
|
}
|
|
if(navigator.clipboard && navigator.clipboard.readText){
|
|
navigator.clipboard.readText().then(function(text){ send(text); })
|
|
.catch(function(){ alert('Liedtext konnte nicht aus der Zwischenablage gelesen werden. Bitte kopiere ihn manuell und nutze „Aus CCLI importieren".'); });
|
|
} else {
|
|
alert('Liedtext konnte nicht gelesen werden. Bitte kopiere ihn manuell und nutze „Aus CCLI importieren".');
|
|
}
|
|
}, 250);
|
|
})();
|
|
BOOKMARKLET;
|
|
|
|
$bookmarkletScript = str_replace('__APP_URL__', $appUrl, $bookmarkletScript);
|
|
|
|
$singleLine = 'javascript:'.preg_replace('/\s+/', ' ', $bookmarkletScript);
|
|
|
|
return response($singleLine, 200, [
|
|
'Content-Type' => 'text/javascript; charset=utf-8',
|
|
'Cache-Control' => 'public, max-age=3600',
|
|
]);
|
|
}
|
|
}
|