const
iMax = 5; // Hier die maximale Senderanzahl einsetzen
IP = '--'; // <-- IP-Adresse
PORT = '--'; // <-- Port
PATH = 'C:\ProgramData\mAirList\6.3\sfk174.exe'; // <-- Pfad
var
sl: TStringList;
pi: IPlaylistItem;
idx, c, i: integer;
EncoderState: array[0 .. iMax] of integer;
procedure PostOnAirScreen(Befehl: string);
begin
ShellExecuteHidden (PATH, 'udpsend ' + IP + Chr(32) + PORT + Chr(32) + Chr(34) + Befehl + Chr(34) + Chr(32) + '-quiet');
//ShellExecute (PATH, 'udpsend ' + IP + Chr(32) + PORT + Chr(32) + Chr(34) + Befehl + Chr(34));
end;
procedure PostOnAirLED(Befehl: string);
begin
ShellExecuteHidden ('C:\Windows\System32\curl.exe', '-s -X POST -d @' + Befehl + '.xml http://admin:12345678@XX:XXXXXX/smartplug.cgi');
end;
procedure OnLoad;
begin
// Eigentlich muss das nicht mal bei jedem Ladevorgang neu passieren aber so sind wir sicher, dass da keiner was verfummelt hat
// und man kann relativ komfortabel die Konfiguration anpassen ohne dass man an die eigentliche Anzeige ran muss
PostOnAirScreen('CONF:LED2:autoflash=True'); // Diese Anzeige soll blinken, blinkede Anzeigen sehen immer wichtig aus.
PostOnAirScreen('CONF:LED3:text=EOF'); // Auf dem Button soll EOF stehen.
PostOnAirScreen('CONF:CONF:APPLY=TRUE');
PostOnAirScreen('LED1:OFF');
PostOnAirScreen('LED2:OFF');
PostOnAirScreen('LED3:OFF');
PostOnAirScreen('LED4:OFF');
PostOnAirScreen('AIR4:OFF');
PostOnAirScreen('AIR4:RESET');
end;
procedure OnEncoderInputToggle(Input: TEncoderInput; NewState: boolean);
begin
if Input = eiMic then begin
if NewState = true then begin
PostOnAirScreen('AIR1:ON');
//PostOnAirLED('on');
end
else begin
PostOnAirScreen('AIR1:OFF');
//PostOnAirLED('off');
end
end;
end;
procedure OnRuntimeDataChange(Key, Value: string);
begin
if Key = 'EncoderStatus' then begin
if Value = ('true') then begin
PostOnAirScreen('AIR4:OFF');
PostOnAirScreen('AIR4:RESET');
end
else begin
PostOnAirScreen('AIR4:ON');
end;
end
else if Key = 'GamepadStatus' then begin
PostOnAirScreen(Value);
end
else if Key = 'EncoderError' then begin
PostOnAirScreen(Value);
end;
end;
procedure OnPlayerStart(PlaylistIndex: integer; PlayerIndex: integer; Item: IPlaylistItem);
begin
idx := CurrentPlaylist.IndexOf(item);
if idx = -1 then begin
SystemLog('Das war kein Element aus unserer Playlist ...');
exit;
end;
sl := TStringList.Create;
c := 0;
while (idx < CurrentPlaylist.GetCount) and (c < 2) do begin
pi := CurrentPlaylist.GetItem(idx);
sl.Add(pi.GetArtist + Chr(32) + 'mit' + Chr(32) + pi.GetTitle );
c := c + 1;
idx := idx + 1;
end;
PostOnAirScreen('NOW:' + sl[0] );
PostOnAirScreen('NEXT:' + sl[1] );
sl.Free;
end;
procedure OnOnAir;
begin
PostOnAirScreen('LED1:ON');
end;
procedure OnOffAir;
begin
PostOnAirScreen('LED1:OFF');
end;
procedure OnPlayerEOFWarning(PlaylistIndex: integer; PlayerIndex: integer);
begin
PostOnAirScreen('LED3:ON');
end;
//procedure OnPlayerStop(PlaylistIndex: integer; PlayerIndex: integer; Duration: TTimeValue; Item: IPlaylistItem);
procedure OnPlayerStateChange(PlaylistIndex: integer; PlayerIndex: integer; OldState: TPlayerState; NewState: TPlayerState; Item: IPlaylistItem);
begin
PostOnAirScreen('LED3:OFF');
end;
procedure OnShutdown; // Sollte den Rechner mit den OnAirScreen herunterfahren, funktioniert bisher aber nicht.
begin
PostOnAirScreen('CMD:SHUTDOWN');
end;
begin
end.
Dann ist es noch ein anderer. Bitte überprüfe alle procedures und vergleiche mit den aktuellen, die Du hier findest. Und poste mal die Fehlermeldung, die immer noch auftaucht.
Hier ist schonmal eine potentielle Ursache: Du gibst die ersten beiden Elemente der StringList aus, ohne zu überprüfen, wie viele Einträge sie überhaupt hat. (Wenn es kein “Next”-Element gibt, dann hat sie nur einen Eintrag - nämlich den aktuellen Titel - und das sl[1] führt dann genau zu der Fehlermeldung “List index out of bounds (1)”).
Edit: Weiterhin kann ich nur empfehlen, den gesamten Block in ein BeginRead...EndRead zu packen, denn die Scripts laufen in einem Hintergrund-Thread ab, und es kann durchaus sein, dass gleichzeitig ein anderer Thread Änderungen an der Playlist vornimmt, wenn du sie nicht sperrst. Insbesondere kann es passieren, dass der andere Thread dir genau in der Millisekunde zwischen GetCountund GetItem(idx) etwas oben aus der Liste rauslöscht, und schon passt alles nicht mehr zusammen.
Daher lieber so machen:
CurrentPlaylist.BeginRead;
try
// hier den Rest der Befehle
finally
CurrentPlaylist.EndRead;
end;
Falls man nicht nur lesen möchte sondern auch Änderungen vornehmen, benutzt man stattdessen BeginUpdate und EndUpdate.
Ersetze die procedure OnPlayerStart durch folgende:
procedure OnPlayerStart(PlaylistIndex: integer; PlayerIndex: integer;
Duration: TTimeValue; Item: IPlaylistItem);
begin
CurrentPlaylist.BeginRead;
try
idx := CurrentPlaylist.IndexOf(item);
if idx = -1 then begin
SystemLog('Das war kein Element aus unserer Playlist ...');
exit;
end;
sl := TStringList.Create;
c := 0;
while (idx < CurrentPlaylist.GetCount) and (c < 2) do begin
pi := CurrentPlaylist.GetItem(idx);
sl.Add(pi.GetArtist + Chr(32) + 'mit' + Chr(32) + pi.GetTitle );
c := c + 1;
idx := idx + 1;
end;
if CurrentPlaylist.GetCount > 0 then
PostOnAirScreen('NOW: ' + sl[0]);
if CurrentPlaylist.GetCount > 1 then
PostOnAirScreen('NEXT: ' + sl[1]);
sl.Free;
finally
CurrentPlaylist.EndRead;
end;
end;
procedure OnOnAir;
begin
PostOnAirScreen('LED1:ON');
end;