Fragen zu Scripts

Ich habe jetzt fast alle meine Scripts fertig um unser aktuelles Playout Programm komplett durch mAirList zu ersetzen.

Automatische Zeitansage funktionniert ja jetzt auch…

Das letzte Script war ein Parser für eine xml Datei um dort die aktuellen Wetterdaten auszulesen und in die Playliste einzufügen.
Wobei sich mir jetzt die Frage stellt ob es eine fertige Funktion gibt wo es (komfortabler) erlaubt die xml Tags auszulesen.
Momentan benutze ich die LoadFromFile Funktion um alle Zeilen in ein Array zu lesen welches dann nach den gewünschten Tags geparsed wird.
Filename : TextFile; als Deklaration geht ja leider nicht.
Bei meinen Versuchen konnte ich aber auch feststellen dass einfache Dephi Funktionen wie Inc(var) nicht von mAirList unterstützt werden.
Gibt es eigentlich eine Liste was man in den Scripts benutzen kann. So langsam bekomme ich (wieder) Übung mit dieser Programmiersprache. Man muss sich nur wieder angewöhnen das begin/end und ; nicht zu vergessen ;D

Ein Script werde ich in den nächsten Tagen noch schreiben welches das Verzeichnis mit den Programmhinweis-Dateien erfasst und dann eines über die Random() Funktion auswählt und in die Playliste schiebt.
Ohne mir jetzt den Wolf zu suchen… gibt es eine Funktion/Befehl welches erlaubt die Dateien in einem Verzeichnis einzulesen? Ansonsten muss ich die Filelist über eine Shell-Funktion erstellen.

Gruss:
-Serge-

Textdateien kann man mit TStringList verarbeiten:

var
  sl: TStringList;

begin
  sl := TStringList.Create;
  try
    sl.LoadFromFile('bla.txt');
  finally
    sl.Free;
  end;
end.

Wenn es um XML-Dateien geht, kannst du auch den eingebauten XML-/DOM-Parser benutzen. Achtung, du brauchst Build 820, den ich gerade hochgeladen habe; in den älteren fehlte ein Teil der benötigten Definitionen im Script-Interface.

Hier mal ein Beispiel, wie man eine .mlp-Datei lädt und die Titel aller dortdrin befindlichen PlaylistItems ausgibt; einmal von Hand durch das DOM gesucht, und einmal mit XPath (wobei von XPath nur ein paar Basisfunktionen unterstützt werden):

var
  doc: IXMLDocument;
  i, j: integer;
  n, n2: IXMLNode;
  nl: IXMLNodeList;

begin
  doc := Factory.CreateXMLDocument;
  doc.SetPreserveWhitespace(false);
  if not doc.Load('d:\temp\test.mlp') then begin
    SystemLog('cannot load file');
    exit;
  end;

  // Manuell durch das DOM hangeln
  for i := 0 to doc.GetDocumentElement.GetChildNodes.GetLength - 1 do begin
    n := doc.GetDocumentElement.GetChildNodes.GetItem(i);
    if n.GetNodeName = 'PlaylistItem' then
      for j := 0 to n.GetChildNodes.GetLength - 1 do begin
        n2 := n.GetChildNodes.GetItem(j);
        if n2.GetNodeName = 'Title' then
          SystemLog(n2.GetText);
      end;
  end;

  // Alternativ mit XPath
  nl := doc.GetDocumentElement.SelectNodes('/PlaylistItem/Title');
  for i := 0 to nl.GetLength - 1 do
    SystemLog(nl.GetItem(i).GetText);
end.

mAirList verwendet die OmniXML-Bibliothek. Die Pascal-Datei mit der Interface-Definition hänge ich hier mal an. Hinweis: Die property-Einträge funktionieren in Scripts nicht; man muss immer die entsprechenden Get- und Set-Methoden verwenden (GetNodeName und SetNodeName statt property NodeName).


XMLInterface.pas (11.3 KB)

Danke Torben!

Die Methode mit XPath ist ja toll :slight_smile:

Komme nur kurz auf meine Frage zurück wie man am einfachsten alle Dateien eines Verzeichnisses in einem Array ablegen kann.
Wird eventuell die FindFirst/FindNext/FindClose Funktion unterstützt?
Es geht drum über Random einen Programmhinweis in die Playliste einzufügen.

Gruss:
-Serge-

Ich habe dir in den neuen Build 822 die Funktion “FindFiles” eingebaut, die ein Verzeichnis nach Dateien durchsucht und als Liste zurückgibt. Die Liste ist vom Typ IStrings. Das ist ein Wrapper für eine TStringList, der den Vorteil hat, dass er reference counted ist, also nicht manuell freigegeben werden muss. Wird bei mAirList an allen möglichen Stellen benutzt, zum Beispiel für die Liste der Attribute eines Playlist-Elements.

Hier ein Beispiel für FindFiles:

[code]
var
i: integer;
str: IStrings;

begin
str := FindFiles(‘g:\incoming*.mp3’, true);
for i := 0 to str.GetCount - 1 do
SystemLog(str.GetItem(i));
end.[/code]

Der zweite Parameter gibt an, ob das Verzeichnis rekursiv (true) oder nicht rekursiv (false) durchsucht werden soll.

Noch ein Beispiel: Einfügen einer zufälligen Datei aus einem Verzeichnis in die Playlist:

var
  str: IStrings;

begin
  str := FindFiles('g:\incoming\*.mp3', false);
  CurrentPlaylist.InsertFile(CurrentPlaylist.GetNextIndex, str.GetItem(Random(str.GetCount)));
end.

Übrigens, mein “Reparaturversuch” von GetNextIndex neulich war eher kontraproduktiv. Im Moment kann es sein, dass die Datei ganz oben eingefügt wird, obwohl gerade ein Player spielt. Ich werde das in Build 823 korrigieren.

1 Like

Hallo Torben,

vielen vielen Dank für dein tolles Support!
Könntest du mir bitte GetNextIndex genauer erklären.

Ich hätte das jetzt (deinem Beispiel entsprechend) folgendermassen in die Playliste eingefügt (so mache ich das momentan mit der Werbung in meinen Tests)

CurrentPlaylist.InsertFile(0, str.GetItem(Random(str.GetCount)));

Was wäre nicht gut daran, respektiv wo liegt der Vorteil GetNextIndex zu benutzen?

Gruss:
-Serge-

GetNextIndex liefert dir die Stelle zurück, an der das nächste zu spielende Element liegt. Also die Position des ersten noch nicht gespielten und derzeit nicht spielenden Elementes.

Ob du das neue Element jetzt bei 0 (ganz oben) oder am GetNextIndex einfügst, spielt für das Ergebnis keine Rolle - die Automation sucht sich eh immer das oberste noch nicht gespielte Element raus, hält sich also im Zweifel nicht an die Reihenfolge in der Playlist. Aber am GetNextIndex einzufügen ist halt “hübscher”, weil man auch optisch genau die Reihenfolge sieht, in der die Sachen gespielt werden.

Der vermeintliche Bugfix, der jetzt wieder rückgängig gemacht wurde, sorgte dafür, dass GetNextIndex manchmal fälschlicherweise 0 zurückgegeben hat.

Alles klar, Danke für die Erklärung.

Stimmt dass es manchmal nicht direkt ersichtlich ist welches das nächste Element in der Playlist ist das gespielt wird.
Im “unattended” Automode ist das aber nicht wirklich wichtig.

Ich denke dass ich jetzt alles mal soweit zusammen habe und kann jetzt erst mal alles so testen ob das Ergebnis das Gleiche ist als bei unserm bestehenden Playout System.

Ausser für die “Overlap”-Funktion wo ich noch keine Lösung für gefunden habe.

Gruss:
-Serge-

Mit Start Next hat nicht funktioniert?

Start Next muss ja über ein Script ausgeführt werden oder habe ich das falsch verstanden.
Und bei StartNext wird der laufende nicht ausgefadet? (Nur interessehalber)

Scripting nutzt mir hier (wahrscheinlich) nix. Was ich brauche ist dass mAirList im AutomationMode NIE ausfadet und nur bei EOF - x Sekunden den nächsten Player starten.
Also eine Funktion wie in diesem Thread bereits gefordert:
http://forum.mairlist.com/index.php/topic,1229.0.html

Der Hintergrund ist dass wir unsere Titel nur minimal überblenden; also quasi voll ausspielen (wir dürfen das hier in Luxemburg)
Deshalb verzichten wir auch auf Cue-Out Punkte, etc…
Alle unsere Titel sind getrimmt auf maximal 500ms Stille am Ende des Tracks und so soll beispielsweise 1,5 Sekunden vor EOF der neue Titel starten ohne den laufenden auszufaden. Der ist ja ohnehin bereits im Ausfaden ausser es ist einer der wenigen wo cold/dry endet. (Dazu habe ich noch eine andere Frage wenn dies geklärt ist)

Ich hoffe ich konnte das jetzt genau genug erklären…

Gruss:
-Serge-

Nein, “Start Next” ist einer der Cue-Punkte, die du im PFL-Dialog setzen kannst. Funktioniert wie Fade Out, blendet aber den vorigen Titel nicht aus.

Wie wäre es, wenn du einfach alle Fade-Out-Punkte löschst (und vom Auto Cue keine neuen erstellen lässt) Dann blendet mAirList nie aus, sondern spielt bis zum Ende. Dann ggf. noch Start-Next-Punkte setzen.

OK,

aber ich kann unmöglich bei über 50.000 Titel den Start Next (manuell) setzen.
Auto-Cue ist deaktiviert. Demnach sind auch keine Fade-Out Punkte vorhanden.

Momentan spielt mAirList die Titel komplet aus und startet dann erst den nächsten.

Wie kann man den Start Next jetzt automatisch setzen? Irgendwie fehlt mir hier der entscheidende Hinweis…

EDIT: Also was ich brauche wäre eine “Auto Start Next” Funktion zum anhaken in der Config, so wie die Auto-Cue Funktion.

Gruss:
-Serge-

Brauche Rat vom Doktor. ;D

Habe mir folgendes überlegt. Ich konvertiere ja unsere Playlists vom xml Format des jetztigen Playout-Systems ins mAirList mlp Format.
Es wäre ein leichtes pro Element in der Playlist folgendes mit einzufügen:

<StartActions> <Action Class="RunScript"> <Filename>C:\MymAirListScripts\SetStartNext.mls</Filename> </Action> </StartActions>

Das StartNext.mls würde für den momentan geladenen Song die Start Next Position markieren und zwar auf EOF - (beispielsweise) 2 Sekunden.

Mich auf diesen Fred referierend:
http://forum.mairlist.com/index.php/topic,4836.0.html

dann würde der Code Schnipsel in etwa so aussehen:

activeItem.SetCuePosition(ptFadeOut, activeItem.GetEffectivePlaybackEnd - SecondsToTimeValue(2));

wobei dies hier ja den FadeOut setzt und ich jetzt nicht die Syntax für StartNext finde…

eventuell so?

activeItem.SetCuePosition(ptStartNext, activeItem.GetEffectivePlaybackEnd - SecondsToTimeValue(2));

???

Wäre eine einfache Lösung jetzt für mich da die “Overlap”-Funktion ja nur im unattended mode (also Auto Mode) gebraucht wird.

Deine Meinung Torben bitte.

Gruss:
-Serge-

// Entfernen Sie die FadeOut Cue-Punkt (setzen Sie ihn auf Null)
activeItem.SetCuePosition(ptFadeOut, 0);

// Cue-Punkte sind relativ zu BOF, so fügen wir die CueIn Cue-Point-Wert um die effektive Dauer
activeItem.SetCuePosition(ptStartNext,
  activeItem.GetEffectivePlaybackDuration 
  + activeItem.GetCuePosition(ptCueIn)
  - SecondsToTimeValue(2));

:wink:

BFN
CAD

[quote=“Cad, post:14, topic:7006”][code]
// Cue-Punkte sind relativ zu BOF, so fügen wir die CueIn Cue-Point-Wert um die effektive Dauer
activeItem.SetCuePosition(ptStartNext,
activeItem.GetEffectivePlaybackDuration

  • activeItem.GetCuePosition(ptCueIn)
  • SecondsToTimeValue (2));
    [/code][/quote]

That’s exactly the same solution that Serge had guessed already

activeItem.SetCuePosition(ptStartNext, activeItem.GetEffectivePlaybackEnd - SecondsToTimeValue(2));

as GetEffectivePlaybackEnd = GetEffectivePlaybackDuration - GetCuePosition(ptCueIn).

Zur Sache:

Ich weiß, Serge, Scripts sind toll, und man möchte nie wieder aufhören welche zu programmieren. Aber in diesem Fall brauchst du kein Script.

Wenn du das XML für die Playlisten sowieso selbst generierst, dann schreib doch einfach den StartNext-Punkt mit rein:

<PlaylistItem Class="File">
  ...
  <CueData>
    <CueDataItem Class="Marker" Type="StartNext" Position="xxx" />
  </CueData>
</PlaylistItem>

Für “xxx” setzt du die Position in mAirList-Einheiten (1/10.000.000 Sekunden) ein.

Da hätte ich ja fast auch selbst drauf kommen können… ::slight_smile:
Einfach StartNext setzen, abspeichern und mpl schauen was drinsteht.

Danke für den Hinweis.

Gurss:
-Serge-

[quote=“Torben, post:15, topic:7006”][quote=“Cad, post:14, topic:7006”][code]
// Cue-Punkte sind relativ zu BOF, so fügen wir die CueIn Cue-Point-Wert um die effektive Dauer
activeItem.SetCuePosition(ptStartNext,
activeItem.GetEffectivePlaybackDuration

  • activeItem.GetCuePosition(ptCueIn)
  • SecondsToTimeValue(2));
    [/code][/quote]

That’s exactly the same solution that Serge had guessed already

activeItem.SetCuePosition(ptStartNext, activeItem.GetEffectivePlaybackEnd - SecondsToTimeValue(2));

as GetEffectivePlaybackEnd = GetEffectivePlaybackDuration - GetCuePosition(ptCueIn). ???[/quote]
(Sorry, but I have to write this in English!)

Correct explanation ;D, but I’m sure you meant:
GetEffectivePlaybackEnd = GetEffectivePlaybackDuration + GetCuePosition(ptCueIn)

If your version was correct, and (for example) CueIn=0’02" and GetEffectivePlaybackDuration=1’58", then in your version, GetEffectivePlaybackEnd=1’56" which is obviously not correct. In this example, GetEffectivePlaybackEnd should be 2’00", unless I very badly misunderstand all this. (?)

BFN
CAD

Sorry, mixed up duration and end.

Ich hätte da noch 'ne kleine Frage wo ich jetzt nicht dahinterkomme…

CurrentPlaylist.InsertFile(x, 'filename');

wenn ich die .chm durchforste ist bei “CurrentPlaylist” die Klasse “IPlaybackControl” als Referenz angegeben.
Bei “IPlaybackControl” gibt’s aber dann wieder keine Methode “InsertFile” ???
Die ist bei “IPlayList” gelistet.

Wie hängt das zusammen?

(Was ich suche ist eine Methode wie “SetTitle” aber halt um das Icon anzugeben wenn man ein Element in die Playliste per Script einfügt. “SetIcon” habe ich jetzt nicht gefunden)

Gruss:
-Serge-

Das Stichwort lautet: Klassenhierarchie (oder hier genauer: Interfacehierarchie). IPlaybackControl ist von IActivePlaylist abgeleitet, das wiederum von IPlaylist abgeleitet sind. Daher erbt IPlaybackControl alle Methoden von IPlaylist, auch wenn das in der CHM-Datei leider so nicht ersichtlich ist. Das Tool, was ich für die Erstellung verwende, fügt leider keine entsprechenden Links ein. Du siehst nur unter dem Punkt “Class Hierarchy”, von welchem Interface das aktuell dargestellte abgeleitet ist. Außerdem gibt es im Inhalt als zweites von oben den Punkt “_Class Hierarchy”, da bekommt man eine baumartige Darstellung.

Zu den Icons siehe hier: http://forum.mairlist.com/index.php/topic,4663.0.html