Playlist files without item file paths?

We’ve just realised that an XML-format MLP file that refers to items in our SQL database contains a complete path to each media file. If files are relocated and the database is updated to reflect their new location, the old location (obviously) remains in previously-stored MLP files.

Is it possible to create an MLP that refers to items by their database identifiers rather than the path to the media file?

Thanks.

I don’t think it is possible with Playlist files but why don’t you create the Playlists within the Database? There you keep the relation, if Database Entries are updated.

No, that’s not possible.

I considered putting them in the database but I can’t imagine how that might work for us. We have aound 80 such lists that must be maintained by our presenters with the tools available from the playout system. Currently the only access to the database from the studio is the search tool.
All of our programming is presented live (i.e. we don’t use automation). These are program-specific lists that hold themes, IDs, stings and the like. Some have a couple of items. Our magazine shows have around 20.
Any suggestions?

Torben, could I request that as a feature? It would be a very useful addition.

Do you think the database interface exposed to the scripting engine offers sufficient functionality for me to fetch items.storage and items.filename using items.idx?

How might I map the XML PlaylistItem ID attribute to items.idx?

Thanks in advance.

I’ve more-or-less answered my own questions. I hacked together a proof-of-concept addition to my file-based list loading function that iterates through the items on the list and colours them red if the filename in the MLP doesn’t match the one stored in the database. This is working well.

I’ll build on this to update the file paths in the MLP if they differ from those in the database. If I can’t reconcile the differences, I’ll disable the items in the playlist.

The only thing I can’t work out is how to do a case-insensitive string comparison in Pascal Script. Google didn’t help. Anyone know if a built-in function exists or do I need to roll my own?

Would be really great if you could share your work.

Is not and will probably never be possible with the current MLP format. Its purpose is to have all metadata in the playlist file, so no DB access is needed anymore.

The playlist saving part in the database (with detection of changed metadata, keeping references vs. full metadata for a particular item etc.) is already very complicated. Having this as a file format would make things even more complicated.

Will probably rather look into offering a way to save “any” playlists (not only those scheduled for a particular date/time) as part of the DB.

You must make our own. Usually you would convert both sides to lower case (with the lowercase function) and then compare.

Thanks for the tip @Torben. I will post the finished script @shorty.xs. It’s not quite there yet. Unfortunately, scripting mAirList isn’t my day job (I spent a good portion of today setting up for a weekend OB).

Cameron

PS: Happy Easter to those who observe it.

I’ve completed the list validation / correction script. I’ve pasted it below. Unfortunately it won’t run out of the box. It depends on our scripting framework. Hopefully the purpose of the missing constants, functions and procedures will be obvious. If they’re not, just ask.

function pathCompare(path1, path2 : string) : boolean;
begin
	Result := lowercase(path1) = lowercase(path2);
end;

procedure invalidatePlaylistItem(pl : IPlayList; pos : integer; reason : string);
var
	bogus, dummy : IPlaylistItem;

begin
	try
		bogus := pl.GetItem(pos);
		dummy := Factory.CreateDummyPlaylistItem();
		dummy.SetColor(LIST_ITEM_INVALID_COLOUR);
		dummy.SetTitle(bogus.GetTitle);
		dummy.SetArtist(reason);
		dummy.SetComment('Original artist: ' + bogus.GetArtist);
		pl.BeginUpdate;
			pl.Delete(pos);
			pl.Insert(pos, dummy);
		pl.EndUpdate;
	except
		SystemLogException('invalidateItem');
	end;
end;

function preenPlaylist(pl : IPlaylist) : boolean;
var
	dbid : string;
	db : IDatabase;
	listDirty : boolean;
	item : IPlaylistItem;
	limit, plpos : integer;
	plitem, dbitem : IFilePlaylistItem;

begin
	listDirty := False;
	limit := pl.GetCount - 1;
	if limit >= 0 then
	begin
		for plpos := 0 to limit do
		begin
			try
				item := pl.GetItem(plpos);
				// We can't assume an MLP contains items that originated in a database.
				// GetDatabase() returns a string of the form: mAirListDB:{UUID} if the
				// item was loaded from a database into the playlist that was saved.
				dbid := item.GetDatabase();
				// Nothing further to do if we can't find a database.
				if dbid = '' then continue;
				db := Instance.GetDatabases().FindByUniqueID(dbid);
				if db = nil then
					RaiseException(erCustomError, 'invalid DB - ' + plitem.GetDatabase());
				plitem := item.AsFile();
				// This will raise an exception if the item is not in the database.
				dbitem := db.CreatePlaylistItem(plitem.GetDatabaseID()).AsFile();
				if not pathCompare(plitem.GetFilename(), dbitem.GetFilename()) then
				begin
					listDirty := True;
					dbitem.SetColor(LIST_ITEM_ATTENTION_COLOUR);
					dbitem.SetComment('location changed from ' + plitem.GetFilename());
					pl.BeginUpdate;
						pl.Delete(plpos);
						pl.Insert(plpos, dbitem);
					pl.EndUpdate;
				end;
			except
				listDirty := True;
				invalidatePlaylistItem(pl, plpos,
					ternary(db = nil, 'db not found', 'item not found'));
				SystemLogException('preenPlayList');
			end;
		end;
	end;
	Result := listDirty;
end;

Cameron