[quote=“Vincent Volmer, post:33, topic:4993”]I only found 3 changes/wishes to make the script more -fool proof- and time stable.
b[/b] When there are no Ads the news-opener is not placed at the right time (start News ##:00:00)
b[/b] When there’s no News (for what reason) the news-open and news-close must be ignored and not being played.
The start of playing the first track of the next hour playlist must be on ##:00:00.
b[/b] Also when no Ads and no News the news-open and news-close must be ignored and not being played.
The start of playing the first track of the next hour playlist must be on ##:00:00.
I hope you understand what I mean and find it useful enough to implement it into the script 
Thanks Cad![/quote]
Firstly, you’re very welcome, Vincent! My pleasure.
OK: I have solved all three problems above, plus the problem (for most users) that a Container’s contents are not individually logged—which would be a disaster for anyone playing paid-for ads.! The solution I came up with was to insert the ad. break, from ad. opener (if any) to news closer (if any), as a big ‘chain’ of Linked items instead of a Container.
In ASSIST mode, the entire ‘chain’ of Linked Items plays out through one Player, just like a Container would; in AUTO mode, each item plays in a separate Player (I’ve tried both and that is how it works in practice). This was the best compromise I could think of between wanting the whole break ‘in one Player’ while still having each played Item logged in the mAirList log.
I’ve ‘tightened up’ the code in general, and each element (ad. break, news, music) is now processed by its own procedure which is called from the main code. And as I said earlier, the script now correctly handles every combination of optional ads and news openers and closers, and presence/absence of ads and news files for the following top-of-hour; unless you find otherwise? I gave it some fairly intensive testing here.
// AdsAndNews v2.2
// Written by Cad Delworth (Clearances Manager, Leith FM, Edinburgh, Scotland)
// based on original code and concepts by Vincent Volmer
// The AdsAndNews script adds a pre-News ad break, top-of-hour News, and the next hour's
// Music Log to the current Playlist. The script sets fixed start times 'intelligently,'
// depending on whether ads and news exist for the next top-of-hour.
// AdsAndNews can thus be run as an hourly scheduled Event for any hour of the day.
const
// Change these directories as required.
ADS_DIR = 'C:\Documents and Settings\Cad.TARDIS\My Documents\mAirList\Testing\';
JINGLES_DIR = 'C:\Documents and Settings\Cad.TARDIS\My Documents\mAirList\Testing\';
MUSIC_DIR = 'C:\Documents and Settings\Cad.TARDIS\My Documents\mAirList\Testing\';
NEWS_DIR = 'C:\Documents and Settings\Cad.TARDIS\My Documents\mAirList\Testing\';
// Change the file name of any opener/closer which you do NOT use to '' (empty string).
// DO NOT DELETE these constants: if you do, the script will not work.
ADS_OPENER = 'Ad breaker sting.mp3';
ADS_CLOSER = 'Ad breaker sting.mp3';
NEWS_OPENER = 'Leith FM - News In sting.mp3';
NEWS_CLOSER = 'Leith FM - News Out sting.mp3';
// Name of script, used to prefix all SystemLog messages (default: 'AdsAndNews-2.2 script: ')
// If you change this, keep a colon and space as the last two characters.
SCRIPTNAME = 'AdsAndNews-2.2 script: ';
// Number of mAirList/BASS time units (10 million) which equals 1 second
ONE_SECOND = 10000000;
// Number of seconds in one day (for TDateTime conversions)
SECONDS_PER_DAY = 86400;
var
bAdsExists, bMusicExists, bNewsExists: boolean;
sAdsFileName, sMusicFileName, sNewsFileName: string;
dtNextHour: TDateTime;
procedure FileErrorMessage(f: string);
// Displays a 'file not found' message
begin
SystemLog(SCRIPTNAME + 'WARNING - file ' + f + ' not found.');
end;
function CheckFileExists(f: string): boolean;
// Returns true if a file exists, false if not (empty string = false)
// Displays a message if file does not exist, UNLESS f is an empty string
var
b: boolean;
begin
if f = '' then
b := false
else
begin
b := FileExists(f);
if b = false then
FileErrorMessage(f);
end;
result := b;
end;
procedure AddFileToPlaylist(pl: IPlaylist; f: String; b: boolean);
// Adds a (usually MP3) file as an Item at the end of a Playlist
// Displays a message if file does not exist
begin
try
pl.Add(Factory.CreatePlaylistItemFromFile(f, b));
except
FileErrorMessage(f);
end;
end;
procedure SetLinked(pi: IPlaylistItem);
// Sets the 'linked to next item' option of a Playlist Item
var
piOptions: TPlaylistItemOptions;
begin
piOptions := pi.GetOptions;
piOptions := piOptions + [pioLinked];
pi.SetOptions(piOptions);
end;
procedure ProcessAdBreak();
// Adds the ad break and News Opener (if any) to the Playlist as Linked items,
// and backtimes the entire break to end at top-of-hour
var
i, iMax: integer;
plAdBreak, plAds: IPlaylist;
sngDuration: single;
begin
// Create the Ad Break Playlist to be added to current Playlist
plAdBreak := Factory.CreatePlaylist;
// Process the ad break if the file exists
if bAdsExists then
begin
// Create a Playlist of the M3U contents
plAds := Factory.CreatePlaylistFromFile(sAdsFileName);
// Add the Ads Opener, if any, to the Ad Break
if CheckFileExists(ADS_DIR + ADS_OPENER) = true then
AddFileToPlaylist(plAdBreak, ADS_DIR + ADS_OPENER, true);
// Add the M3U Playlist to the Ad Break
plAdBreak.AppendPlaylist(plAds);
// Add the Ads Closer, if any, to the Ad Break
if CheckFileExists(ADS_DIR + ADS_CLOSER) = true then
AddFileToPlaylist(plAdBreak, ADS_DIR + ADS_CLOSER, true);
end;
// If News exists, add the News Opener (if any) to the Ad Break,
// so we can backtime the whole Ad Break (including News Opener) to top-of-hour
if bNewsExists
and (CheckFileExists(NEWS_DIR + NEWS_OPENER) = true) then
AddFileToPlaylist(plAdBreak, NEWS_DIR + NEWS_OPENER, true);
// Link all items in the Ad Break, except the last item
// (the Ad Break MAY be followed by Music)
iMax := plAdBreak.GetCount - 2;
// Only Link Items if we have at least two Items in the Ad Break Playlist
if iMax >= 0 then
begin
for i := 0 to iMax do
begin
SetLinked(plAdBreak.GetItem(i));
end;
end;
// If News will follow, make the last item Linked
// (this will be the final ad., the Ad Closer, or the News Opener, as appropriate)
if bNewsExists = true then
SetLinked(plAdBreak.GetItem(plAdBreak.GetCount - 1));
// Calculate the Ad Break start time...
// Convert Ad Break duration to seconds
sngDuration := plAdBreak.GetDuration / ONE_SECOND;
// Convert to a TDateTime value
sngDuration := sngDuration / SECONDS_PER_DAY;
// Set fixed start time for first item in Ad Break, backtimed from top-of-hour
plAdBreak.GetItem(0).SetStartTime(sttFixed, dtNextHour - sngDuration);
// Append the Ad Break Playlist to the current Playlist
CurrentPlaylist.AppendPlaylist(plAdBreak);
end;
procedure ProcessNews();
// Adds the News (and News Closer, if any) to the Playlist as Linked items,
// with a fixed start of top-of-hour
var
piNews: IPlaylistItem;
begin
piNews := Factory.CreatePlaylistItemFromFile(sNewsFileName, true);
if piNews.ErrorCheck = true then
begin
// Set fixed start time on-the-hour for the News Bulletin
piNews.SetStartTime(sttFixed, dtNextHour);
// Check whether we need a News Closer
if CheckFileExists(NEWS_DIR + NEWS_CLOSER) = true then
begin
// Link the News to the News Closer
SetLinked(piNews);
// Add the News to the Playlist
CurrentPlaylist.Add(piNews);
// Add the News Closer to the Playlist
AddFileToPlaylist(CurrentPlaylist, NEWS_DIR + NEWS_CLOSER, true);
end
else
// No News Closer, add the News to the Playlist
// (NOT Linked, because Music will be next)
CurrentPlaylist.Add(piNews);
end
else
FileErrorMessage(sNewsFileName);
end;
procedure ProcessMusic();
// Adds the next hour's Music Log to the Playlist
// If there was no News, give the first Item a fixed start time of top-of-hour
var
plMusic: IPlaylist;
begin
try
plMusic := Factory.CreatePlaylistFromFile(sMusicFileName);
if bNewsExists = false then
// No news, so set first Music Item to start on-the-hour
plMusic.GetItem(0).SetStartTime(sttFixed, dtNextHour);
// Add the Music to the current Playlist
CurrentPlaylist.AppendPlaylist(plMusic);
except
FileErrorMessage(sMusicFileName);
end;
end;
// MAIN CODE STARTS HERE //
begin
// Calculate start of next hour as Delphi TDateTime
dtNextHour := (Trunc(Now * 24) + 1) / 24;
// Generate the file names of ads, music, and news for following top-of-hour
sAdsFileName :=
ADS_DIR
+ FormatDateTime('yyyy-mm-dd-hh', Now)
+ '-Ads.m3u';
sNewsFileName :=
NEWS_DIR
+ FormatDateTime('yyyy-mm-dd-hh', dtNextHour)
+ '-News.mp3';
sMusicFileName :=
MUSIC_DIR
+ FormatDateTime('yyyy-mm-dd-hh', dtNextHour)
+ '-Music.m3u';
// Check whether these files exist...
// Use a custom function which reports missing files to the user,
// and store the results to use later on in the script
bAdsExists := CheckFileExists(sAdsFileName);
bNewsExists := CheckFileExists(sNewsFileName);
bMusicExists := CheckFileExists(sMusicFileName);
// Add the 'existing' elements to the current Playlist
// News Opener (if any) is handled as part of the ad. break pre-News
if bAdsExists or bNewsExists then
ProcessAdBreak;
if bNewsExists then
ProcessNews;
if bMusicExists then
ProcessMusic;
end.
I hope that both Vincent and Tony approve of the ‘new! improved!’ v2.2. 
Enjoy!
BFN
CAD