Vollautomatische Ausspielung von Wiederholungen und Vorproduzierten Sendungen

Malte vs. Script
Script: 2
Malte: 0

Neuer Fehler, ob ich das jemals lerne… Dabei habe ich damals in der Schule sogar etwas Pascal gelernt. Auf Hochmodernen 286ern mit Bernsteinfarbenen Monitoren. :disappointed_relieved:

const
  MAX_COUNT = 3;

var
  pl: IPlaylist;
  i: integer;

begin
  pl := Factory.CreatePlaylist;

  CurrentPlaylist.BeginUpdate;
  try
    for i := 0 to CurrentPlaylist.GetCount - 1 do
      if CurrentPlaylist.GetItem(i).GetItemType = pitShow then begin
        pl.Add(CurrentPlaylist.GetItem(i));
        if pl.GetCount = MAX_COUNT then break;
      end;

     item.AutoSearchPosition(ptCueIn);
     item.AutoSearchPosition(ptFadeOut);
     item.AutoSearchPosition(ptCueOut);
  finally
    CurrentPlaylist.EndUpdate;
  end;
end.

Ich muss dieses Thema noch mal hoch bringen, kann mir da jemand weiter helfen, was an meinem Script falsch ist?

Das „end.“ fehlt?

Ergänzte Grüße

TSD

Vor allem fehlt die Deklaration von “item”. Für welche Items soll das AutoCue denn durchgeführt werden? Für alle, die vorher in der Liste “pl” notiert wurden? Dann wohl eher so:

for i := 0 to pl.GetCount - 1 do begin
   pl.GetItem(i).AutoSearchPosition(ptCueIn);
   pl.GetItem(i).AutoSearchPosition(ptFadeOut);
   pl.GetItem(i).AutoSearchPosition(ptCueOut);
end;

Danke, das war tatsächlich nur ein Copy and Paste Fehler hier im Forum. Im Script hatte ich das end. mit drin. Ich korrigiere das weiter oben in meinen Posts.

d.H. ich brauche eine 2. Schleife. Die erste, die mir den Typ Sendung (Show) raus sucht aber nur maximal die ersten 3 Elemente durchsucht und die 2. Schleife die die Elemente bearbeitet.

Laufen die einfach nacheinander? Ich hätte jetzt angenommen, die müssten in einander verschachtelt sein?

Dann komme ich auf dieses Konstrukt.

const
  MAX_COUNT = 3;

var
  pl: IPlaylist;
  i: integer;

begin
  pl := Factory.CreatePlaylist;

  CurrentPlaylist.BeginUpdate;
  try
    for i := 0 to CurrentPlaylist.GetCount - 1 do
      if CurrentPlaylist.GetItem(i).GetItemType = pitShow then begin
        pl.Add(CurrentPlaylist.GetItem(i));
        if pl.GetCount = MAX_COUNT then break;
      end;

	for i := 0 to pl.GetCount - 1 do begin
		pl.GetItem(i).AutoSearchPosition(ptCueIn);
		pl.GetItem(i).AutoSearchPosition(ptFadeOut);
		pl.GetItem(i).AutoSearchPosition(ptCueOut);
	end;
  finally
    CurrentPlaylist.EndUpdate;
  end;
end.

EDIT nach dem Stundenwechsel: Sehr schön, der Fehler ist schon mal weg.

Der nächste Schritt, den ich machen möchte ist: Den Titel und Interpreten aus dem MP3 Tag neu lesen.

Ich nehme an, dass das irgendwie mit: IMetadataHandler > ReadNativeTags funktioniert.

Die untere for Schleife um sowas erweitern oder ist das fehlt mir da wieder irgend etwas?

pl.GetItem(i).IMetadataHandler(ReadNativeTags);

Das würde ich an oberster Stelle einfügen, bevor die Cue-Werte ermittelt werden.

EDIT oder ist es:
IFilePlaylistItem > function GetFileTagData ( iTag : string ) : string
?

Hatte diesen Beitrag gefunden: Zugriff auf ID3-Tags mit mAirList-Script
Weiß aber nicht ob der a) noch aktuell ist und b) kann ich daraus auch nicht das richtige Script ableiten.

Wenn du sie nacheinander schreibst, laufen sie auch nacheinander :wink: Natürlich könnte man auch auf die zweite Schleife verzichten und alles direkt in der ersten machen (und dabei mitzählen, wie viele man schon bearbeitet hat).

const
  MAX_COUNT = 3;

var
  i: integer;
  count: integer;

begin
  CurrentPlaylist.BeginUpdate;
  try
    count := 0;
    for i := 0 to CurrentPlaylist.GetCount - 1 do
      if CurrentPlaylist.GetItem(i).GetItemType = pitShow then begin
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptCueIn);
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptFadeOut);
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptCueOut);

        count := count + 1;
        if count = MAX_COUNT then break;
      end;
  finally
    CurrentPlaylist.EndUpdate;
  end;
end.

Probier mal das:

Factory.CreateMetadataHandler(CurrentPlaylist.GetItem(i)).ReadNativeTags;

Danke!

Das ist genau so’n Ding was ich dann immer nicht verstehe. (Das war Westfälisch: Immer nicht verstehe :joy:)
Die Cue Daten kann ich einfach vom Item Lesen aber um das lesen der Tags, muss ich wieder eine weitere Funktion drum herum bauen.
Ob ich das jemals in meinen Kopf kriege…:exploding_head:

Also, dann mal ganz langsam:

  • Factory ist ein Objekt, das Methoden zur Verfügung stellt, über die man alle möglichen anderen Arten von Objekten erzeugen kann.
  • In diesem Fall wollen wir über die Funktion CreateMetadataHandler ein Objekt vom Typ IMetadataHandler erzeugen, mit dem wir die Tags auslesen können.
  • Die Funktion CreateMetadataHandler bekommt dabei als Parameter das PlaylistItem übergeben, auf dem der Handler arbeiten soll - damit der direkt weiß, mit welcher Datei und welchem Item er es zu tun hat.
  • Dann wird dessen Methode ReadNativeTags aufgerufen, um die ID3-Tags zu lesen und in den PlaylistItem-Datensatz zu kopieren.

“Unabgekürzt” (und besser zu verstehen) würde das so aussehen:

item := CurrentPlaylist.GetItem(i);
handler := Factory.CreateMetadataHandler(item);
handler.ReadNativeTags;

Durch die Kurzschreibweise ersparen wir uns die ganzen Variablendeklarationen.

Du siehst, die Interna von mAirList sind manchmal sehr kompliziert. Aber bieten doch eine Menge Funktionalität. Die Script-Engine ist euer Guckloch in diese Welt.

Um die Sache etwas intuitiver zu machen, könnte ich dem IPlaylistItem eine Methode CreateMetadataHandler geben, die nur eine Abkürzung für Factory.CreateMetadataHandler(item) ist. Dann würde es so aussehen:

CurrentPlaylist.GetItem(i).CreateMetadataHandler.ReadNativeTags;

Wäre das besser zu verstehen?

Übrigens, bei den Typen mit “I” vorne (IPlaylistItem, IMetadataHandler, …) handelt es sich allesamt um “Interfaces”, also “indirekte” Verweise auf Objekte. Die dann wiederum Methoden haben, die man aufrufen kann.

Die Verwendung von Interfaces statt normaler Objektreferenzen erlaubt es in Delphi, dass man “reference counting” macht. Also Objekte, die sich selbst aus dem Speicher löschen, sobald niemand mehr auf sie zugreift. Daher der Umweg über Interfaces. Beim Programmieren immer die doppelte Arbeit, da man sowohl das Interface als auch das implementierende Objekt definieren muss. Aber am Ende hat es nur Vorteile.

1 Like

PS: Ich liebe das Markdown vom neuen Forum.

Danke für die Ausführungen. Lange- und kurze Schreibweise bringe ich schon passend zusammen. Auch wenn ich die Syntax immer noch nicht verstanden habe. Schauen wir mal.

Ja, das ist wirklich klasse.

Jetzt muss ich mal sehen, wie ich das noch unterbringe.

Ich würde erst mal den Dateinamen, des aktuellen Items in eine Variable schreiben und .cue anhängen und dann das lesen der Cue Datei triggern.
Wobei ich da sicherlich noch abfangen muss, dass die Cue Datei nicht immer existiert und nur wenn sie existiert, soll sie auch gelesen werden.

const
  MAX_COUNT = 3;

var
  i: integer;
  count: integer;
  cue: IFilePlaylistItem;

begin
  CurrentPlaylist.BeginUpdate;
  try
    count := 0;
    for i := 0 to CurrentPlaylist.GetCount - 1 do
      if CurrentPlaylist.GetItem(i).GetItemType = pitShow then begin
	    Factory.CreateMetadataHandler(CurrentPlaylist.GetItem(i)).ReadNativeTags;
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptCueIn);
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptFadeOut);
        CurrentPlaylist.GetItem(i).AutoSearchPosition(ptCueOut);
		cue := FilePlaylistItem.GetFilename(CurrentPlaylist.GetItem(i))+'.cue';
		CurrentPlaylist.GetItem(i).GetCueData.LoadFromCueSheet(cue:);
        count := count + 1;
        if count = MAX_COUNT then break;
      end;
  finally
    CurrentPlaylist.EndUpdate;
  end;
end.

Ich muss dieses Thema noch mal aufgreifen.

Ein Re-Do des AutoCue ist ja seit Version 6.2 Obsolet, das kann ich ja einfach beim Element anhaken.
Wo ich aber immer noch nicht weiter bin ist das neuladen eines Cue-Sheets, was seit Version 6.2 ja noch deutlich interessanter geworden ist, weil man die jetzt sinnvoll bei einer Aufzeichnung erzeugen kann.

Also muss jetzt folgendes passieren.

  1. Syndication Zulieferung, gleichbleibender Dateiname an gleichbleibendem Verzeichnis. Ist ein Cue-Sheet vorhanden, dieses importieren. Ist keins vorhanden, ggf. vorhandene Extra-Cuepunkte löschen.

  2. Ausspielung von Wiederholungen. Der MiniScheduler muss sich anhand von Variablen die richtige Datei suchen. YYYY/KW/Wochentag/Stunde/*.mp3 (es kann hier nur eine liegen, Position im Vezeichnisbaum und Dateiname, sind jedes mal anders. Dann immer AutoCue und falls vorhanden, Cue-Sheet laden. Gelöscht werden muss hier nix, das passiert bereits vorher, es sind also niemals extra Cue-Punkte im Tag.

Hat da jemand eine Idee?

Ja, wenn die Cue-Daten einmal eingelesen sind, kann man sie sowohl im Element, im MMD file, in der Datenbank oder in der Plalyliste speichern, genau so wie alle andren META daten auch.

Entsprechend bleiben die erhalten. Das nutzen wir mehrfach täglich.

Wenn sich die Datei unter gleichem Dateinamen ändert, funktioniert das natürlich nicht mehr. Dazu habe ich noch einen anderen Thread offen aber offensichtlich lässt sich das im Moment auch nicht scripten.

Ja genau, das meinte ich… Beispiel: Ich kriege eine vorproduzierte Sendung Meine_ganz_tolle_Sendung.mp3 und das entsprechende Cue Sheet Meine_ganz_tolle_Sendung.mp3.cue. Diese wurde produziert am 19. August 2019. Nun folgt das Update (die Sendung läuft wöchentlich) der beiden Dateien am 26. August 2019. Inhalt der mp3 und der mp3.cue Datei sind jetzt natürlich anders. Die Titelübertragung ist dann die vom 19. August (Cue-Sheet) und nicht die neue vom 26. August ?!?

Und wenn die vorproduzierte Sendung den Anhang [Nummer der Kalenderwoche] erhält - entweder vom Zulieferer oder von dir?

Vielleicht kann man auch was basteln, dass man das Upload-Datum automatisiert vor das .mp3 einfügen lässt? :thinking:

Das Thema hatte ich hier: Vollautomatische Ausspielung von Wiederholungen und Vorproduzierten Sendungen
Schon mal auf gemacht, bisher aber leider noch keine Lösung gefunden. In der Scripting engine fehlt offensichtlich der Zugriff auf die extra Cues, jedenfalls konnte mir bisher noch niemand sagen, wie ich damit in Scripten umgehen müsste.

Ja… Manchmal ist das so eine Sache mit dem Wald und den Bäumen.

Ich habe mich mal wieder an meine Vollautomatisierung gemacht und das Script von weiter oben, vereinfacht. Wir gehen einfach die ganze Playliste durch, suchen nach dem Item Element “Sendung”, laden erst mal den ID3 Tag und falls eine existiert, auch die Cue-Datei.

var
  i: integer;
  cue: IFilePlaylistItem;

begin
  CurrentPlaylist.BeginUpdate;
  try
    for i := 0 to CurrentPlaylist.GetCount - 1 do
      if CurrentPlaylist.GetItem(i).GetItemType = pitShow then begin
        Factory.CreateMetadataHandler(CurrentPlaylist.GetItem(i)).ReadNativeTags;
        cue := FilePlaylistItem.GetFilename(CurrentPlaylist.GetItem(i))+'.cue';
        CurrentPlaylist.GetItem(i).GetCueData.LoadFromCueSheet(cue);
      end;
  finally
    CurrentPlaylist.EndUpdate;
  end;
end.

Muss ich das laden des Cue-Sheets in eine weitere “Try” Schleife packen oder reicht das erste try vor der for-Schleife dafür auch noch aus?
Ich habe es noch nicht getestet aber passt das halbwegs oder bin ich total auf dem Holzweg?

Hmm :man_facepalming: ich bekomme einen Error (10:81): Type mismatch.

Was mache ich denn schon wieder falsch? :thinking:

Du in diesem Falle gar nichts:

Das kann so nicht funktionieren, da CreateMetaDataHandler ein Objekt vom Typ IFilePlaylistItem benötigt, und nicht IPlaylistItem.

Allerdings bliebe Dein Code auch in der nächsten Zeile hängen:

[Error] (11:16): Unknown identifier 'FilePlaylistItem'

@Torben?


Sonntägliche Grüße

TSD

In meiner Zeitzone ist heute Samstag… wo bist du denn?