The DAM Forum
Welcome, Guest. Please login or register.
September 23, 2014, 03:23:51 PM

Login with username, password and session length
Search:     Advanced search
28018 Posts in 5138 Topics by 2910 Members
Latest Member: kbroch
* Home Help Search Login Register
+  The DAM Forum
|-+  Software Discussions
| |-+  Scripting
| | |-+  EM2 playlist from media list script
« previous next »
Pages: [1] Print
Author Topic: EM2 playlist from media list script  (Read 3554 times)
Kevin Forsmo
Newbie
*
Posts: 31



View Profile
« on: September 05, 2009, 04:59:21 PM »

I have this great idea that I'm going to start organizing videos with EM2.  I'm currently hung up on creating m3u playlists from my nicely filtered media list in EM2.  I know not a shred of VB syntax.  Before I go off and try to learn how to do this, can someone let me know if it's as simple as I think it is?  The idea is to have all my movies categorized, rated, etc. so that I can get a list of files I'd like to go into a playlist to show up in the EM2 list pane.  From there, all that needs to happen is a text file needs to be written with a header and two lines for each entry that's in the list.  Let's say I filter my collection so that only two files are showing in the EM2 list: filename1.avi and filename2.avi.  I need to write a text file (with the extension m3u) that has the following contents:

#EXTM3U
#EXTINF:,filename1
M:\movies\source\filename1.avi
#EXTINF:,filename2
M:\movies\source\filename2.avi

Conceptually this sounds simple, would it be relatively easy to cobble together?  I have some programming experience, but nothing between applications or COM (just MATLAB).  I'm glad to learn to do it, I just want to get a sense of where I'm going to run into trouble. 
Thanks in advance.

Kevin
Logged
johnbeardy
Administrator
Hero Member
*****
Posts: 1813


View Profile WWW
« Reply #1 on: September 05, 2009, 10:55:31 PM »

Not too difficult - use my "Write data to (SQL) text file" as a model.

Do you have Excel? There are some small differences between the its VBA code and VBS, but it's easier to develop a script in Excel's VBA environment and then copy it over to Notepad. Errors are easier to fix, and you can run code one line at a time (F8) and mouse over variable values.

John
Logged
ianw
Full Member
***
Posts: 162


View Profile
« Reply #2 on: September 06, 2009, 02:50:45 AM »

I've come at this from a different angle, and suggest that XML/XSL is the way to go.  You also get a solution that works in iView and xMedia and on PC and Mac.

Following XSL script creates an M3U file.  It also fills in the missing part in Kevin's example in that between the #EXTINF: and the following comma should be the duration of the track in seconds, although it does appear to be optional.

Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:template match="/">
  <xsl:text>#EXTM3U</xsl:text>
  <xsl:text>&#xD;</xsl:text>
  <xsl:for-each select="CatalogType/MediaItemList/MediaItem">
   <xsl:text>#EXTINF:</xsl:text>
   <xsl:call-template name="duration2seconds">
    <xsl:with-param select="MediaProperties/Duration" name="duration"/>
   </xsl:call-template>
   <xsl:text>,</xsl:text>
   <xsl:value-of select="AssetProperties/Filename"/>
   <xsl:text>&#xD;</xsl:text>
   <xsl:value-of select="AssetProperties/Filepath"/>
   <xsl:text>&#xD;</xsl:text>
  </xsl:for-each>
 </xsl:template>
 <xsl:template name="duration2seconds">
  <xsl:param name="duration"/>
  <xsl:variable name="hours" select="number(substring($duration,1,2))"/>
  <xsl:variable name="minutes" select="number(substring($duration,4,2))"/>
  <xsl:variable name="seconds" select="number(substring($duration,7,2))"/>
  <xsl:value-of select="format-number((($hours * 3600)+($minutes * 60)+$seconds),'###')"/>
 </xsl:template>
</xsl:stylesheet>

Save the above in a file e.g. M3UCreator.xsl.  The .xsl at the end is the most important bit.  Then go to your catalogue and select the tracks you want.  Now go the Make menu option and select XML Data File.  You need to have the Media Properties box ticked.  I would recommend not ticking anything in the Create Folders and Options section.  At the bottom is an XSL Transform button.  Hit this and a Choose File box will come up.  You need to navigate to and select the XSL file you've just saved from above.  Once you done this you need to hit the Make button.  This will prompt you for the name of the output file.  Whatever you call it you must add the .m3u yourself, otherwise it will default to .xml which is of no use.  Now save the file and voila!

I've test the output from the above in Windows Media Player and Real Player and no problems.  The only 'flaw' is that iView / xMedia doesn't extract the Title of a music track from the file so the above script puts the file name in, including the .mp3 or .wma etc.  However both Windows Media Player and Real Player appear smart enough to show the correct title.

Hope this helps.  Any questions etc...

Ian
Logged
johnbeardy
Administrator
Hero Member
*****
Posts: 1813


View Profile WWW
« Reply #3 on: September 06, 2009, 03:01:06 AM »

Nice idea, Ian.

John
Logged
Kevin Forsmo
Newbie
*
Posts: 31



View Profile
« Reply #4 on: September 07, 2009, 08:59:28 AM »

Wow, I didn't expect to have it written for me.  Thanks!
It works like a charm except for one thing: Winamp doesn't tolerate the carriage return after the last entry (or anywhere for that matter).  This means it needs to treat either the first or last entry differently, or be able to "backspace" after the loop completes.  Another issue (minor) is that it fails if there is no duration (some file types that aren't supported by EM2 but I have added just to catalog don't have durations).  I will do some research to modify the code to test if a duration exists and just add the comma if not.
Thanks again, it probably saved me a week of flailing.

Kevin
Logged
ianw
Full Member
***
Posts: 162


View Profile
« Reply #5 on: September 07, 2009, 09:35:38 AM »

Kevin,

I tested it on MP3 and WMA files that all had durations.  This should be easy to fix this but depends on what iView/xMedia does.  If you can select one such file in your catalogue and then do the Make... XML Data File... option.  However this time do not select the XSL file.  When it prompts you to save the file put in any name with a .xml extension.  If you can post the contents of this file I will be able to see if the duration tag is missing, because there is not value, or it is present with a null value, or knowing how quirky it may be that it's there with a weird value!  The fix may depend on this.  Beware of what you post in case you have any personal details present!  I'm at work at the moment but will have a look when I get home in a few hours time.  I did a Google on the M3U specification and for streaming files the duration should be set to -1.  As much (or littlle) as know about iView / xMedia I don't think you can use it to catalogue a website so that file locations are URLs.  If you can then it would need another fix to get around this.

With regards to the carriage return problem it is easy to not put one in at the end of the file. In your example I assume this means that there is nothing after filename2.avi?  If so then the following code should fix it.  The <xsl:text>&#xD;</xsl:text> is the code that writes a carriage return, hex character D, which is ASCII 13, a carriage return.  Instead of writing after the header record and after each media entry I've changed it to write before each media entry.  This isn't tested in anyway but should do the job.

Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
  <xsl:text>#EXTM3U</xsl:text>
  <xsl:for-each select="CatalogType/MediaItemList/MediaItem">
   <xsl:text>&#xD;</xsl:text>
   <xsl:text>#EXTINF:</xsl:text>
   <xsl:call-template name="duration2seconds">
    <xsl:with-param select="MediaProperties/Duration" name="duration"/>
   </xsl:call-template>
   <xsl:text>,</xsl:text>
   <xsl:value-of select="AssetProperties/Filename"/>
   <xsl:text>&#xD;</xsl:text>
   <xsl:value-of select="AssetProperties/Filepath"/>
  </xsl:for-each>
</xsl:template>
<xsl:template name="duration2seconds">
  <xsl:param name="duration"/>
  <xsl:variable name="hours" select="number(substring($duration,1,2))"/>
  <xsl:variable name="minutes" select="number(substring($duration,4,2))"/>
  <xsl:variable name="seconds" select="number(substring($duration,7,2))"/>
  <xsl:value-of select="format-number((($hours * 3600)+($minutes * 60)+$seconds),'###')"/>
</xsl:template>
</xsl:stylesheet>

What I don't understand is your "or anywhere for that matter" comment.  It could be that it needs both carriage return and linefeed characters in there.  In this case each <xsl:text>&#xD;</xsl:text> would need to be changed to <xsl:text>&#xD;&#xA;</xsl:text>  Again I can't test this at the moment.

Will post again later...

Ian
Logged
Kevin Forsmo
Newbie
*
Posts: 31



View Profile
« Reply #6 on: September 07, 2009, 12:00:56 PM »

Hi Ian,

the files that I have that don't have durations have no entry for Duration in the media properties (the field just isn't there in the xml file you suggested I create).  This results in a not-a-number (NaN) in the resultant m3u file.  I cut the duration template out of your code so that whether the duration is there or not, it always just prints the comma and filename, as in:

#EXTINF:,filename.avi

It would be nice to have error-handling (and if you're bored by all means go nuts), but you've already gotten me on my feet and I can potentially take it from here.  It's not the end of the world to have winamp not show the duration in the playlist.  In fact, after playing each file the duration is included so I can just resave the playlist from winamp after stepping through all the files once.  Again, it's not nearly as critical as being able to use the rating/labeling/grouping power of EM to do the filtering and then being able to pop a playlist out of it.

The linefeed was indeed the problem.  I mentioned "or anywhere"  because my initial attempt at fixing this was to try the obvious and stick the CRs before each line within the loop, at which point I would up with an empty line between the first line in the file and the first entry in the playlist.  It's been a long time since my Hello world! days in undergraduate C programming, so I forgot the difference between CR and LF Smiley.  I guess working within the MATLAB environment and never needing to interact with the OS or FS or any other application has spoiled me into a non-programmer.

Lastly, is it easy to comment out lines?  If you wind up not implementing the error-checking for the existence of the duration field ,I'd prefer to comment out your duration lines rather than have a separate file.  Thanks again!

If you don't wind up fixing the

Thanks again for all your help, it's saved me much time to have this nice feature.

John: I did initially grab your write to text file to begin my attack, so thanks for that.  I'll likely still take a look in excel to see if I can make sense of it, thanks for the tip about the "free" development environment I already own.

Kevin
« Last Edit: September 07, 2009, 12:06:56 PM by Kevin Forsmo » Logged
ianw
Full Member
***
Posts: 162


View Profile
« Reply #7 on: September 07, 2009, 12:23:00 PM »

Kevin,

Thanks for the info on the duration field.  If it's not there it's an easy fix to do, simply putting a test on the node and if there include the duration details.  Code below includes this fix and also the changes in the previous post including making the end of a line be both carriage return and new line characters.

Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:template match="/">
  <xsl:text>#EXTM3U</xsl:text>
  <xsl:for-each select="CatalogType/MediaItemList/MediaItem">
   <xsl:text>&#xD;&#xA;</xsl:text>
   <xsl:text>#EXTINF:</xsl:text>
   <xsl:if test="MediaProperties/Duration">
    <xsl:call-template name="duration2seconds">
     <xsl:with-param select="MediaProperties/Duration" name="duration"/>
    </xsl:call-template>
   </xsl:if>
   <xsl:text>,</xsl:text>
   <xsl:value-of select="AssetProperties/Filename"/>
   <xsl:text>&#xD;&#xA;</xsl:text>
   <xsl:value-of select="AssetProperties/Filepath"/>
  </xsl:for-each>
 </xsl:template>
 <xsl:template name="duration2seconds">
  <xsl:param name="duration"/>
  <xsl:variable name="hours" select="number(substring($duration,1,2))"/>
  <xsl:variable name="minutes" select="number(substring($duration,4,2))"/>
  <xsl:variable name="seconds" select="number(substring($duration,7,2))"/>
  <xsl:value-of select="format-number((($hours * 3600)+($minutes * 60)+$seconds),'###')"/>
 </xsl:template>
</xsl:stylesheet>

It is easy to comment out code - you need to use the put it inside of code as follows: <!-- commented out -->

Note that the above XSL is a flavour of XML, so is verry fussy about the structure i.e. all tags that are opened must be closed correctly and nesting of tags is correct.  If you have HTML experience then you have to be careful as that is not so strict - which is why so many web pages look different in different browsers.

Anyway glad to help.

Ian
Logged
Pages: [1] Print 
« previous next »
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!