get($url); if ($response->successful()) { $html = $response->body(); $text = strip_tags($html); $text = trim($text); return $text !== '' ? $text : null; } } catch (\Exception) { // Best-effort: Fehler stillschweigend behandeln } return null; } /** * Übersetzungstext auf Slides verteilen, basierend auf der Zeilenanzahl jeder Slide. * * Für jede Gruppe (nach order sortiert) und jede Slide (nach order sortiert): * Nimm so viele Zeilen aus dem übersetzten Text, wie die Original-Slide Zeilen hat. * * Beispiel: * Slide 1 hat 4 Zeilen → bekommt die nächsten 4 Zeilen der Übersetzung * Slide 2 hat 2 Zeilen → bekommt die nächsten 2 Zeilen * Slide 3 hat 4 Zeilen → bekommt die nächsten 4 Zeilen */ public function importTranslation(Song $song, string $text): void { $translatedLines = explode("\n", $text); $offset = 0; // Alle Gruppen nach order sortiert laden, mit Slides $groups = $song->groups()->orderBy('order')->with([ 'slides' => fn ($query) => $query->orderBy('order'), ])->get(); foreach ($groups as $group) { foreach ($group->slides as $slide) { $originalLineCount = count(explode("\n", $slide->text_content ?? '')); $chunk = array_slice($translatedLines, $offset, $originalLineCount); $offset += $originalLineCount; $slide->update([ 'text_content_translated' => implode("\n", $chunk), ]); } } $this->markAsTranslated($song); } /** * Song als "hat Übersetzung" markieren. */ public function markAsTranslated(Song $song): void { $song->update(['has_translation' => true]); } /** * Übersetzung eines Songs komplett entfernen. * * Löscht alle text_content_translated Felder und setzt has_translation auf false. */ public function removeTranslation(Song $song): void { // Alle Slides des Songs über die Gruppen aktualisieren $slideIds = SongSlide::whereIn( 'song_group_id', $song->groups()->pluck('id') )->pluck('id'); SongSlide::whereIn('id', $slideIds)->update([ 'text_content_translated' => null, ]); $song->update(['has_translation' => false]); } }