Für einen einzelnen Cuepunkt (Cue In, Fade Out oder Cue Out) reicht:
item.AutoSearchPosition(ptFadeOut); // oder ptCueIn oder ptCueOut
Cue-Sheet einzeln einlesen geht so:
item.GetCueData.LoadFromCueSheet('C:\irgendwo.cue');
Für einen einzelnen Cuepunkt (Cue In, Fade Out oder Cue Out) reicht:
item.AutoSearchPosition(ptFadeOut); // oder ptCueIn oder ptCueOut
Cue-Sheet einzeln einlesen geht so:
item.GetCueData.LoadFromCueSheet('C:\irgendwo.cue');
OK, ich stehe immer noch total auf dem Schlauch.
Bisher habe ich an mAirlist Basisfunktionen wie Encoder herumgescriptet. Ich muss erst mal verstehen, wie ich das Script dazu bewege, bestimmte Elemente einer Playliste zu bearbeiten.
Geht das nur in der Hauptplayliste oder kann ich das schon in der Datenbank triggern, bevor die ausspielende Instanz die Playliste überhaupt geladen hat?
Ich habe hier von KFB ein Script gefunden, das müsste als Ausgangsbasis ja funktionieren, nur eben nicht Hooks bearbeiten sondern CuePunkte und Cuesheet:
const
MAX_COUNT = 2;
var
pl: IPlaylist;
hook: IPlaylistItem;
i: integer;
begin
pl := Factory.CreatePlaylist;
CurrentPlaylist.BeginUpdate;
try
for i := CurrentPlaylist.GetNextIndex to CurrentPlaylist.GetCount - 1 do
if CurrentPlaylist.GetItem(i).GetItemType = pitMusic then begin
pl.Add(CurrentPlaylist.GetItem(i));
if pl.GetCount = MAX_COUNT then break;
end;
hook := Factory.CreateHookContainer(pl);
container.GetPlaylist.Add(hook);
finally
CurrentPlaylist.EndUpdate;
end;
end.[/code]
Ich habe das also mal so umgebaut, evetl. muss ich den Elementtyp noch mal ändern, spielt aber für die Funktion, erstmal keine Rolle.
const
MAX_COUNT = 3;
var
pl: IPlaylist;
cue: IPlaylistItem;
i: integer;
begin
pl := Factory.CreatePlaylist;
CurrentPlaylist.BeginUpdate;
try
for i := CurrentPlaylist.GetNextIndex to CurrentPlaylist.GetCount - 1 do
if CurrentPlaylist.GetItem(i).GetItemType = pitMusic then begin
pl.Add(CurrentPlaylist.GetItem(i));
if pl.GetCount = MAX_COUNT then break;
end;
cue := item.AutoSearchPosition(ptCueIn);
cue := item.AutoSearchPosition(ptFadeOut);
cue := item.AutoSearchPosition(ptCueOut);
finally
CurrentPlaylist.EndUpdate;
end;
end.
EDIT: gehört also eigentlich eher in die Foren Kategorie Scripting, ggf. bitte verschieben.
CurrentPlaylist steht, wieder Name schon vermuten lässt, für die “aktuelle Playlist”. Je nach Kontext, in dem das Script läuft. Als Event oder manuell gestartet ist das die aktuelle Playlist im Ausspieler. Als “Nachbearbeitungs-Script” in einer Datenbank-Aktion hingegen bezieht sich CurrentPlaylist auf die aus der DB geladene Playlist, bevor sie dann in die Ausspielung kopiert wird.
Natürlich kann man auch Scripts bauen, die sich einen Sendeplan aus der DB laden, ihn bearbeiten und dann zurückschreiben.
Wenn man ein bestimmtes Element sucht, geht man normalerweise einfach die CurrentPlaylist von 0 bis GetCount-1 durch und vergleicht Interpret oder Titel oder irgendein Attribut. Du musst halt wissen, woran du deine Datei erkennst
Übrigens liefert AutoSearchPosition keinen Wert zurück, sondern trägt ihn direkt in das IPlaylistItem ein.
OK, sieht so aus als wäre das Nachbearbeitungsscript, das was ich brauche. Mal sehen ob ich etwas dazu finde, wie das getriggert wird. Ich versinke also mal etwas in der Doku. Bitte nicht spoilern, nur wer selber sucht, lernt auch was.
Ja, das ist klar soweit. Ich bin mir noch nicht sicher ob ich die Sendung in einem Stück verwende oder die Version, die in 3 Teilen angeliefert wird aber das spielt ja keine Rolle. Ich bin hier von 3 Elementen pro Sendestunde ausgegangen, die ich dann entsprechend Markiere, vermutlich werde ich nach dem Elemettyp Sendung, suchen, der dann 3 mal auftaucht und bearbeitet werden soll.
OK, ich brauche die Variable cue also gar nicht und wenn ich einfach alle durchlaufe kann ich break und MAXCOUNT auch rauswerfen.
const
MAX_COUNT = 3;
var
pl: IPlaylist;
i: integer;
begin
pl := Factory.CreatePlaylist;
CurrentPlaylist.BeginUpdate;
try
for i := CurrentPlaylist.GetNextIndex 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.
Das einlesen des Cuesheets fehlt auch noch dazu müsste ich aus dem Item das ich gerade bearbeite den Pfad samt Dateinamen extrahieren und ein .cue anhängen um es der entsprechenden Funktion zu übergeben, das Sheet neu zu lesen.
OK, das war schon mal einfach, ohne in die Doku zu schauen.
Selbsterklärende Dialogboxen sind schon was feines.
Auf meinem Weg zur Vollautomatischen Ausspielung unserer Wiederholgunen, bin ich nun mit den externen Elementen ein Stück weiter. (Finaler Test steht noch aus und kann wegen des laufenden Programms, gerade nicht durchgeführt werden)
Jetzt geht es hier weiter, mit dem Eincuen, das sollte mit dem Script oben, funktionieren und was mir auch noch fehlt:
OK, ich habe hier einen Fehler, wenn das Script ausgeführt werden soll.
const
MAX_COUNT = 3;
var
pl: IPlaylist;
i: integer;
begin
pl := Factory.CreatePlaylist;
CurrentPlaylist.BeginUpdate;
try
for i := CurrentPlaylist.GetNextIndex 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.
Da erscheint dieser Fehler, scheint also irgend etwas nicht zu stimmen.
Einen CurrentPlaylist.GetNextIndex
gibt es nicht, da die Liste ja noch nicht in die Ausspielung geladen ist. Setz also einfach eine 0 ein.
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.
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 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 )
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…
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.CreateMetadataHandler
ein Objekt vom Typ IMetadataHandler
erzeugen, mit dem wir die Tags auslesen können.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.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.
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.
Syndication Zulieferung, gleichbleibender Dateiname an gleichbleibendem Verzeichnis. Ist ein Cue-Sheet vorhanden, dieses importieren. Ist keins vorhanden, ggf. vorhandene Extra-Cuepunkte löschen.
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?