Script to fix dumb Zen MX playlist format

Download and get help for different MediaMonkey Addons.

Moderators: Peke, Gurus

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Mon Jul 04, 2011 5:01 pm

Lowlander wrote:I thought it was under Device Profile > Options > Playlists, but I no longer see it anywhere.

http://www.ventismedia.com/mantis/view.php?id=5933
Any idea when it was taken out (which build) and why? I looked at the bug lists for the beta of MM4 and I noticed that they did have it at one point, but that it is the only playlist sync menu option suggested as part of development that seems to have disappeared. I did email tech support about it but I was wondering if you knew.

Thanks!

Lowlander
Posts: 46262
Joined: Sat Sep 06, 2003 5:53 pm
Location: MediaMonkey 5

Re: Script to fix dumb Zen MX playlist format

Post by Lowlander » Mon Jul 04, 2011 5:48 pm

I don't know as I don't use it, but I do remember having seen it in past builds.
Lowlander (MediaMonkey user since 2003)

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Thu Jul 07, 2011 10:47 pm

UPDATE: After communicating with Tech Support, the issue in the bugfixes for MM4 that supplies the option to use 8.3 DOS filenames in the device syncronization options has been reopened and assigned.
http://www.ventismedia.com/mantis/view.php?id=6255

As much as that is AWESOME, I would appreciate the update on the script as a backup plan. After all, the feature has been removed once during the beta process; there's no guarantee that it will make it to the final version. (Prerequisite grain of salt. At the rate Tech Support is going, I am seriously considering buying MM Gold. They've had some of the most concise and prompt support I've gotten from a music management software.)

UPDATE 2: This function has now officially been held until Media Monkey 4.1 at the earliest. Any news on script fix for runtime error 53 on line 101, column 0?

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Tue Aug 02, 2011 5:15 pm

Stoffel, are you still out there? O javascript guru of the Zen MX script?

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Wed Sep 07, 2011 3:58 pm

PawWriter wrote:Stoffel, are you still out there? O javascript guru of the Zen MX script?
Sorry, haven't been here fore a while. Didn't expect much traffic on the subject any more. Well, I haven't messed with the new MM 4 yet.
Will have a look in the next day and try a fix.

See you

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Wed Sep 07, 2011 4:29 pm

stoffel wrote:
PawWriter wrote:Stoffel, are you still out there? O javascript guru of the Zen MX script?
Sorry, haven't been here fore a while. Didn't expect much traffic on the subject any more. Well, I haven't messed with the new MM 4 yet.
Will have a look in the next day and try a fix.

See you
Ok, I went for a quit shot! Installed MM4 1426, Copied and activated my script. Plugged my good old ZEN MX and started "Fix dumb ZEN MX playlist" and voila some new playlists where created with correct short names. Nice dialog popups, No error messages!

So at the moment I see no compatibility problems concerning MM4!

My question: Where is the problem ;-) Can you give some more hints. What playlist is in your playlist folder, are the music files referenced in your playlist file situated ON your ZEN device?

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Wed Sep 07, 2011 4:43 pm

stoffel wrote:
stoffel wrote:
PawWriter wrote:Stoffel, are you still out there? O javascript guru of the Zen MX script?
Sorry, haven't been here fore a while. Didn't expect much traffic on the subject any more. Well, I haven't messed with the new MM 4 yet.
Will have a look in the next day and try a fix.

See you
Ok, I went for a quit shot! Installed MM4 1426, Copied and activated my script. Plugged my good old ZEN MX and started "Fix dumb ZEN MX playlist" and voila some new playlists where created with correct short names. Nice dialog popups, No error messages!

So at the moment I see no compatibility problems concerning MM4!

My question: Where is the problem ;-) Can you give some more hints. What playlist is in your playlist folder, are the music files referenced in your playlist file situated ON your ZEN device?
Once more: All files reference in the PL MUST be in the referenced folder on the ZEN device. Otherwise the PL wouldn't make any sense on the device anyway. When you synchronize your PL with you ZEN, MM copys the PL AND all reference music files. So this gives you the correct file layout! You should not copy any PL to the playlist folder directly by hand!

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Wed Sep 07, 2011 5:03 pm

Ok, I found the problem! MM4 now generates the path to songnames with leading drive letter 'P:' That's a problem for my script!
Solution: Go to device 'My ZEN', Tab 'Options' section 'Playlists' and check 'Enforce relative paths'. Then export your PL again.
Now 'P:' is replaced by '..' which is fine for my script.

Will do a new version that handles both path variants in the next day, so that checking 'Enforce relative paths' will not be necessary any more.

CU

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Thu Sep 08, 2011 6:22 am

A new version for MM4. No need for checking 'Enforce relative paths' anymore. Very untested!

Have fun :D

Code: Select all

// Fix stupid ZEN MX Bug: Playlists must define their tracknames in 8.3 DOS style
// Convert every playlist '<name>.m3u' found in /playlist to '@ <name>.m3u'. Original files are not changed
//
// (c) Stefan Skopnik (sskopnik(at)web(dot)de)
//
// 01.01.2010 fixes for W7, don't generate if newpl exists and is newer than orgpl, changed NewPlName
// 14.01.2010 scan for drive modified, test for dir exist, more detailed messages, change naming schema again to: '@ <name>.m3u'
// 08.09.2011 fixes for Zen Style 100 and MM4

/*
Installation:
1.) Copy this file to C:\<Program>\MediaMonkey\Scripts\FixZenMXPlaylist.js
	(Windows7: This dir is write protected, you have to change this!)

2.) Append to file C:\<Program>\MediaMonkey\Scripts\scripts.ini:
[FixZenMXPlaylist]
FileName=FixZenMXPlaylist.js
ProcName=FixZenMXPlaylist
Order=1
DisplayName=Fix dumb ZEN MX playlist
;DisplayName=Korrektur von ZEN MX Playlisten
Description=Fix dumb ZEN MX playlist
;Description=Korrektur von ZEN MX Playlisten
Language=JScript
ScriptType=0

3.) Plugin Zen MX and create PLs in MediaMonkey

4.) Send PL to 'My ZEN'

5.) Run this Script from Extras / Scripts / Fix dumb ZEN MX playlist

6.) Unplug ZEN MX

7.) Enjoy your MM PL on ZEN MX. You find them under '@ <ORGNAME>.m3u
*/

var	MyLang      = 'en',						// Define your language: 'en' = English, 'de' = German
    MyDevice    = 'ZENMX',					// Define your player device here, see DeviceConfig for possible devices (ZENMX,ZENSTYLE100)

	OutDrive    = "?",						// Define your Zen MX Drive ('X:') or leave "?" to let script find device
	OutDir      = "\\Playlist",				// Define location of PL on device
	Scriptname  = "FixZenMXPlaylist.js",
	Version     = "1.03"
	NewPlName   = "@ %1.%2",				// Mask for new Playlist filenames, %1 is replaced with old filenameprefix, %2 is replaced with old filenamesuffix
											// Don't forget to modify re_exclfn accordingly
	
	re_exclfn 	 = /@.*\.m3u$/,				// RE for Filenames to be EXCLUDED from conversion (must match NewPlName)
	
	re_inclfn 	 = /\.m3u$/,				// RE for Filenames to be INCLUDED into conversion
	re_ignoreln  = /^#/,					// RE for lines to be ignored during conversion
	
	DeviceConfig = {						// Deviceconfiguration. You have to look into the registry!
		'ZENMX'       : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_MX",
		'ZENSTYLE100' : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_Style_Series&Rev_0200"
	},
	
	objFso = new ActiveXObject("Scripting.FileSystemObject"),
	objDic = new ActiveXObject("Scripting.Dictionary"),
	C_ForReading = 1,
	Lang_rc = {
		'de' : {
			msg0 : "Keine Playliste im Verzeichnis '%2' erstellt.",
			msg1 : "Folgende %1 neue Playlisten wurden im Verzeichnis '%2' erstellt:\n\n",
			msg2 : "Folgende neue Playliste wurde im Verzeichnis '%2' erstellt:\n\n",
			msg4 : "Kein Zen MX Spieler gefunden!",
			msg5 : "Zen MX Spieler in Laufwerk '%1' gefunden.\nPlaylisten konvertieren?",
			msg6 : "Unterverzeichnis '%1' auf Laufwerk '%2' nicht gefunden!",
			msg7 : "Zen MX Spieler gefunden, aber Unterverzeichnis '%1' nicht gefunden!"
		},
		'en' : {
			msg0 : "No playlist created in directory '%2'.",
			msg1 : "%1 new playlists where created in directory '%2':\n\n",
			msg2 : "%1 new playlist was created in directory '%2':\n\n",
			msg4 : "No Zen MX Player found!",
			msg5 : "Found Zen MX Player in drive '%1'.\nConvert Playlists?",
			msg6 : "Subdirectory '%1' missing on drive '%2'!",
			msg7 : "Zen MX Player found, but subdirectory '%1' missing!"
		}
	},
	Lang = Lang_rc[MyLang];

// some utillity functions
	
function sprintf() {
var savearg = arguments;

	return savearg[0].replace(new RegExp("%(\\d+)","g"),
			    function ($0, $1, $2) { return savearg[$1]; }
		   );
}

function getDriveLetter(i) {
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
	s;
	s = str.charAt(i);
	return(s + ":");
}

function JS2VBArray(objJSArray) {
	objDic.RemoveAll();
    for (var i = 0; i < objJSArray.length; i++ ) {
        objDic.add(i,objJSArray[i]);
    }
    return objDic.Items();
}

function getShortPath(filespec, nodrive) {
var f = objFso.GetFile(filespec),
	ret = f.ShortPath;
	
	if (nodrive) ret = ret.substr(2);
	return(ret);
}

function convColltoArr(col) {
var ret = new Array();

	for (var e = new Enumerator(col), i = 0; !e.atEnd(); e.moveNext(), i++) {
		ret[i] = e.item();
	}
	return ret;
}

function stripDriveLetter(fn) {
var start = fn.indexOf(":");

	return fn.slice(++start);	
}

function getPath(fn) {
var stop = fn.lastIndexOf("\\");

	if (stop==-1) return "";
	return fn.slice(0,stop);
}

function getFilename(fn) {
var start = fn.lastIndexOf("\\");

	return fn.slice(++start);
}

function getFilenamePrefix(fn) {
var ret = getFilename(fn),
	stop = ret.lastIndexOf(".");
	
	if (stop==-1) return ret;
	return ret.slice(0,stop);
}

function getFilenameSuffix(fn) {
var ret = getFilename(fn),
	start = ret.lastIndexOf(".");
	
	if (start==-1) return "";
	return ret.slice(++start);
}

function messageBox(s,t,barr) {
	return SDB.MessageBox(s, t, JS2VBArray(barr));
}

// ---

function FixZenMXPlaylist() {
var	fc,
	fin,
	fout,
	orgfile,
	newfile,
	newfilearr = new Array(),
	nrfiles = 0,
	ret,
	devlist,
	i,
	f_org,
	f_new,
	actmsg;
	
	/*
	 * Find the Drive letter of Zen MX
	 * Well, I have no real idea what ActiveDeviceList is supposed to return. XP and W7 return complety different FriendlyNames. 
	 * In W7 the second Drive is never returned.
	 * So this is a rather dumb method:
	 * 
	 * Scan all Drives with correct vendor&Product Name.
	 * 		If you find drive with existing subdir <OutDir>  use it!
	 * 		else give up!
	 * 		
	 * This was tested with XP / W7 successfully
	 */
	if (OutDrive == "?") {
		devlist = SDB.Device.ActiveDeviceList(DeviceConfig[MyDevice]); // You have to look into the registry!
		for (i = 0; i < devlist.Count;i++) {
			OutDrive = "!";
			//messageBox(i + ": (" + devlist.DeviceID(i) + ") " + devlist.FriendlyName(i) + " " + 
			//	devlist.DeviceInst(i) + " " + getDriveLetter(devlist.DriveLetterIndex(i)), mtInformation, new Array(mbOk) );
			TestOutDrive = getDriveLetter(devlist.DriveLetterIndex(i));
			// if (devlist.FriendlyName(i) == "Creative ZEN MX USB Device") break;
			if (objFso.FolderExists(TestOutDrive + OutDir)) {
				OutDrive = TestOutDrive;
				break;
			}
		}
	}	
	switch (OutDrive) {
		case "?":	messageBox(Lang.msg4, mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
					return(-1);
		case "!":	messageBox(sprintf(Lang.msg7, OutDir), mtError, new Array(mbOk.toString()));
					return(-1);
		default:	ret = messageBox(sprintf(Lang.msg5, OutDrive), mtConfirmation, new Array(mbOk, mbCancel));
					if (ret == mrCancel) return (-2);
	}	
	
	// Ok, we want this folder! Else exit
	if (!objFso.FolderExists(OutDrive + OutDir)) {
		messageBox(sprintf(Lang.msg6, OutDir, OutDrive), mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
		return(-1);
	}	

	objDir = objFso.GetFolder(OutDrive + OutDir);

	for (fc = new Enumerator(objDir.files); !fc.atEnd(); fc.moveNext()) {
		ele = fc.item();
		if (re_inclfn.test(ele.Name) && !re_exclfn.test(ele.Name)) {
			// WScript.Echo("File: " + ele.Path);

			orgfile = ele.Path;
			newfile = getPath(orgfile) + "\\" + sprintf (NewPlName, getFilenamePrefix(orgfile), getFilenameSuffix(orgfile));
			
			// Don't generate if newfile already exists and is newer than oldfile
			if (objFso.FileExists(newfile)) {
				f_org = objFso.GetFile(orgfile);
				f_new = objFso.GetFile(newfile);
				if (f_new.DateLastModified > f_org.DateLastModified) continue;
			}
			nrfiles++;
			newfilearr.push(getFilename(newfile));
			
			fin = objFso.OpenTextFile(orgfile, C_ForReading, false);
			fout = objFso.CreateTextFile(newfile, true);

			while (!fin.AtEndOfLine) {
				l = fin.ReadLine();
				
				l = stripDriveLetter(l);
				
				if (!re_ignoreln.test(l)) {
					sn = getShortPath(OutDrive + l, true);
					l = sn;
				}
				fout.WriteLine(l);

			}
			fin.Close();
			fout.Close();
		}
	}
	switch (nrfiles) {
		case 0:		actmsg = 'msg0'; break
		case 1: 	actmsg = 'msg2'; break
		default:	actmsg = 'msg1'; 
	}	
	messageBox(sprintf(Lang[actmsg], nrfiles, OutDrive + OutDir) + newfilearr.join(", "), 
		mtInformation, new Array(mbOk.toString())
	);
	return (0);
}

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Thu Sep 08, 2011 11:58 pm

HURRAY!

Stoffel, you are truly a Java guru! For the first time since I got this player, I have editable playlists!

Thank you and thank you again!

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Thu Sep 15, 2011 4:18 pm

Ok, here's another "final" version fore MM 3/4.
Little more tested and implementing some new features.
See inline doc. Maybe you want to give:

ReplaceOrgPl : true

a try.

Have fun ;-)

Code: Select all

// Fix stupid ZEN MX Bug: Playlists must define their tracknames in 8.3 DOS style
// Convert every playlist '<name>.m3u' found in /playlist to '@ <name>.m3u' changing tracknames to 8.3 DOS style.
// By default original files are not changed
//
// (c) Stefan Skopnik (sskopnik(at)web(dot)de)
//
// 01.01.2010 fixes for W7, don't generate if newpl exists and is newer than orgpl, changed NewPlName
// 14.01.2010 scan for drive modified, test for dir exist, more detailed messages, change naming schema again to: '@ <name>.m3u'
// 08.09.2011 fixes for Zen Style 100 and MM4 (now works with MM3 and MM4)
// 12.09.2011 New Configsystem. New flags DeleteOrgPl and ReplaceOrgPl.
//            Now you can decide if you want to:
//            - delete the original pl-file after conversion (DeleteOrgPl=true) leaving only the converted @pl-file
//            - replace the old pl-file with the converted version (ReplaceOrgPl=true) preserving the original name.
//              (This may be the default in the future, Here only converted files are taken into account)
/*

Installation:
-------------

1.) Copy this file to <MediaMonkeyInstallDir>\Scripts\FixZenMXPlaylist.js
    (Windows7: This dir is write protected, you have to change this!)

2.) Append to file <MediaMonkeyInstallDir>\Scripts\scripts.ini:
< --- COPY AFTER THIS LINE --->
[FixZenMXPlaylist]
FileName=FixZenMXPlaylist.js
ProcName=FixZenMXPlaylist
Order=1
DisplayName=Fix dumb ZEN MX playlist
;DisplayName=Korrektur von ZEN MX Playlisten

Description=Fixes ZEN MX playlist by converting filepath into 8.3 DOS format
;Description=Korrektur von ZEN MX Playlisten durch konvertieren der Dateinamen/pfade in das 8.3 DOS Format
Language=JScript
ScriptType=0
<--- COPY BEFORE THIS LINE --->

3.) (Re)start MM

4.) Plugin Zen MX and create PLs in MediaMonkey

5.) Send PL to 'My ZEN'

6.) Run this Script from Extras / Scripts / Fix dumb ZEN MX playlist

7.) Unplug ZEN MX

8.) Enjoy your MM PL on ZEN MX. You find them under '@ <ORGNAME>.m3u


Configuration:
-------------

This script should work 'out of the box' with Zen MX Player using english laguage.
If you like you can configure the script in some aspects. See 'Config' for options

*/

var Config = {                              // All user changeable config settings go here
        Language     : 'en',                // Set your prefered language (Currently 'en' = English, 'de' = German is supported)
        DeleteOrgPl  : false,               // Set true if you want to delete original playlist files after conversion
        ReplaceOrgPl : false,               // Set true if you want to replace original playlist with converted version
        Device       : 'ZENMX',             // Define your player device here, see 'DeviceConfig' for possible devices (ZENMX,ZENSTYLE100)
        NewPlName    : "@ %1.%2",           // Mask for new Playlist filenames,
                                            // %1 is replaced with old filenameprefix, %2 is replaced with old filenamesuffix
        ReExclFn     : /@.*\.m3u$/          // RE for Filenames to be EXCLUDED from conversion (must match 'NewPlName')
    },
    
    re_inclfn    = /\.m3u$/,                // RE for Filenames to be INCLUDED into conversion
    re_ignoreln  = /^#/,                    // RE for lines to be ignored during conversion
    OutDrive     = "?",                     // Define your Zen MX Drive ('X:') or leave "?" to let script find device
    OutDir       = "\\Playlist",            // Define location of PL on device
    Scriptname   = "FixZenMXPlaylist.js",
    Version      = "1.04",
    FileComment  = "#!@ 8.3 DOS converted by %1 V%2",
    re_flag      = /^#!@ 8.3 DOS converted/,

    DeviceConfig = {                        // Deviceconfiguration. You have to look into the registry!
        'ZENMX'       : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_MX",
        'ZENSTYLE100' : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_Style_Series&Rev_0200"
    },

    Lang_rc = {
        'de' : {
            msg0 : "Es wurden keine Playlisten im Verzeichnis '%2' erstellt.",
            msg1 : "Folgende %1 neue Playlisten wurden im Verzeichnis '%2' erstellt:\n\n",
            msg2 : "Folgende neue Playliste wurde im Verzeichnis '%2' erstellt:\n\n",
            msg4 : "Kein Zen MX MP3-Player gefunden!",
            msg5 : "Zen MX MP3-Player in Laufwerk '%1' gefunden.\nPlaylisten konvertieren?",
            msg6 : "Unterverzeichnis '%1' auf Laufwerk '%2' nicht gefunden!",
            msg7 : "Zen MX MP3-Player gefunden, aber Unterverzeichnis '%1' fehlt!"
        },
        'en' : {
            msg0 : "No playlists created in directory '%2'.",
            msg1 : "%1 new playlists where created in directory '%2':\n\n",
            msg2 : "%1 new playlist was created in directory '%2':\n\n",
            msg4 : "No Zen MX MP3-Player found!",
            msg5 : "Found Zen MX MP3-Player in drive '%1'.\nConvert Playlists?",
            msg6 : "Subdirectory '%1' missing on drive '%2'!",
            msg7 : "Zen MX MP3-Player found, but subdirectory '%1' missing!"
        }
    },
    Lang = Lang_rc[Config.Language],
    
    objFso = new ActiveXObject("Scripting.FileSystemObject"),
    objDic = new ActiveXObject("Scripting.Dictionary"),
    C_ForReading = 1
;

// some utillity functions

function sprintf() {
var savearg = arguments;

    return savearg[0].replace(new RegExp("%(\\d+)","g"),
                function ($0, $1, $2) { return savearg[$1]; }
           );
}

function getDriveLetter(i) {
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    s;
    s = str.charAt(i);
    return(s + ":");
}

function JS2VBArray(objJSArray) {
    objDic.RemoveAll();
    for (var i = 0; i < objJSArray.length; i++ ) {
        objDic.add(i,objJSArray[i]);
    }
    return objDic.Items();
}

function getShortPath(filespec, nodrive) {
var f = objFso.GetFile(filespec),
    ret = f.ShortPath;

    if (nodrive) ret = ret.substr(2);
    return(ret);
}

function convColltoArr(col) {
var ret = new Array();

    for (var e = new Enumerator(col), i = 0; !e.atEnd(); e.moveNext(), i++) {
        ret[i] = e.item();
    }
    return ret;
}

function stripDriveLetter(fn) {
var start = fn.indexOf(":");

    return fn.slice(++start);
}

function getPath(fn) {
var stop = fn.lastIndexOf("\\");

    if (stop==-1) return "";
    return fn.slice(0,stop);
}

function getFilename(fn) {
var start = fn.lastIndexOf("\\");

    return fn.slice(++start);
}

function getFilenamePrefix(fn) {
var ret = getFilename(fn),
    stop = ret.lastIndexOf(".");

    if (stop==-1) return ret;
    return ret.slice(0,stop);
}

function getFilenameSuffix(fn) {
var ret = getFilename(fn),
    start = ret.lastIndexOf(".");

    if (start==-1) return "";
    return ret.slice(++start);
}

function messageBox(s,t,barr) {
    return SDB.MessageBox(s, t, JS2VBArray(barr));
}

// ---

function FixZenMXPlaylist() {
var fc,
    fin,
    fout,
    orgfile,
    newfile,
    newfilearr = new Array(),
    nrfiles = 0,
	bufferline,
    ret,
    devlist,
    i,
    f_org,
    f_new,
    actmsg;

    /*
     * Find the Drive letter of Zen MX
     * Well, I have no real idea what ActiveDeviceList is supposed to return. XP and W7 return complety different FriendlyNames.
     * In W7 the second Drive is never returned.
     * So this is a rather dumb method:
     *
     * Scan all Drives with correct vendor&Product Name.
     *   If you find drive with existing subdir <OutDir> use it!
     *   else give up!
     *
     * This was tested with XP / W7 successfully
     */
    if (OutDrive == "?") {
        devlist = SDB.Device.ActiveDeviceList(DeviceConfig[Config.Device]); 
        for (i = 0; i < devlist.Count;i++) {
            OutDrive = "!";
            //messageBox(i + ": (" + devlist.DeviceID(i) + ") " + devlist.FriendlyName(i) + " " +
            //    devlist.DeviceInst(i) + " " + getDriveLetter(devlist.DriveLetterIndex(i)), mtInformation, new Array(mbOk) );
            TestOutDrive = getDriveLetter(devlist.DriveLetterIndex(i));
            // if (devlist.FriendlyName(i) == "Creative ZEN MX USB Device") break;
            if (objFso.FolderExists(TestOutDrive + OutDir)) {
                OutDrive = TestOutDrive;
                break;
            }
        }
    }
    switch (OutDrive) {
        case "?":   messageBox(Lang.msg4, mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
                    return(-1);
        case "!":   messageBox(sprintf(Lang.msg7, OutDir), mtError, new Array(mbOk.toString()));
                    return(-1);
        default:    ret = messageBox(sprintf(Lang.msg5, OutDrive), mtConfirmation, new Array(mbOk, mbCancel));
                    if (ret == mrCancel) return (-2);
    }

    // Ok, we want this folder! Else exit
    if (!objFso.FolderExists(OutDrive + OutDir)) {
        messageBox(sprintf(Lang.msg6, OutDir, OutDrive), mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
        return(-1);
    }

    objDir = objFso.GetFolder(OutDrive + OutDir);

    for (fc = new Enumerator(objDir.files); !fc.atEnd(); fc.moveNext()) {
        ele = fc.item();
        if (re_inclfn.test(ele.Name) && !Config.ReExclFn.test(ele.Name)) {
            // WScript.Echo("File: " + ele.Path);

            orgfile = ele.Path;
            newfile = getPath(orgfile) + "\\" + sprintf (Config.NewPlName, getFilenamePrefix(orgfile), getFilenameSuffix(orgfile));

            // Don't generate if newfile already exists and is newer than oldfile
            if (objFso.FileExists(newfile)) {
                f_org = objFso.GetFile(orgfile);
                f_new = objFso.GetFile(newfile);
                if (f_new.DateLastModified > f_org.DateLastModified) continue;
            }

            fin = objFso.OpenTextFile(orgfile, C_ForReading, false);
            fout = objFso.CreateTextFile(newfile, true);

            l = fin.ReadLine();
            if (!l || re_flag.test(l)) continue;    // was the file already converted? don't do it again
            bufferLine = l;                         // else buffer the first line

            nrfiles++;
            newfilearr.push(getFilename(Config.ReplaceOrgPl ? orgfile : newfile));

            fout.WriteLine(sprintf(FileComment, Scriptname, Version)); // mark new file as converted
            while (!fin.AtEndOfStream) {

                if (bufferLine) {   
                    l = bufferLine;
                    bufferLine = undefined;
                } else {
                    l = fin.ReadLine();
                }

                if (!re_ignoreln.test(l)) {
                    l = stripDriveLetter(l);    // MM4 by default generates filepath with drive letters, we don't want them!
                    sn = getShortPath(OutDrive + l, true);
                    l = sn;
                }
                fout.WriteLine(l);

            }
            fin.Close();
            fout.Close();

            if (Config.DeleteOrgPl || Config.ReplaceOrgPl)    objFso.DeleteFile(orgfile, true);
            if (Config.ReplaceOrgPl)                          objFso.MoveFile(newfile, orgfile);
        }
    }
    switch (nrfiles) {
        case 0:     actmsg = 'msg0'; break
        case 1:     actmsg = 'msg2'; break
        default:    actmsg = 'msg1';
    }
    messageBox(sprintf(Lang[actmsg], nrfiles, OutDrive + OutDir) + newfilearr.join(", "),
        mtInformation, new Array(mbOk.toString())
    );
    return (0);
}

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Fri Sep 16, 2011 10:33 pm

Hi there,
Newest build (1433) comes back with the following error: Error #53 - File Not Found; Line 136, Column 0. Any idea what's causing it?
Thanks again!

Edit: The script will work for one playlist. Then, when I delete the original M3U off of my player and run the script again, it will do the next playlist. Repeat the process for each list I have and eventually I can get all of my playlists converted. Did I mess something up somewhere so that it won't convert multiple lists at once?

Edit 2: Only the first 7 tracks of any given playlist will convert into the new format. Strange.

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Sun Sep 18, 2011 11:48 am

PawWriter wrote:Hi there,
Newest build (1433) comes back with the following error: Error #53 - File Not Found; Line 136, Column 0. Any idea what's causing it?
Thanks again!

Edit: The script will work for one playlist. Then, when I delete the original M3U off of my player and run the script again, it will do the next playlist. Repeat the process for each list I have and eventually I can get all of my playlists converted. Did I mess something up somewhere so that it won't convert multiple lists at once?

Edit 2: Only the first 7 tracks of any given playlist will convert into the new format. Strange.
Well, I tested again, found a small bug where @-files of length 0 are created even if nothing has to be done. But a can't reproduce any of your (really strange) phenomenons !
- file not found error was the main fix of this release! Should not occur any more!
- Script works for one playlist only: Can't believe :o Tested with 28!
- Only the first 7 tracks are converted: :o :o :o

Very strange!! Tested with 1426,1433 without any error! What config do you use? Try with a clean playlist dir an create a new pl via MM

PawWriter
Posts: 11
Joined: Mon Jul 04, 2011 2:27 am

Re: Script to fix dumb Zen MX playlist format

Post by PawWriter » Tue Sep 20, 2011 9:19 pm

Hi there,
The "one playlist at a time" error happens only when "Force relative paths" is selected. When that option isn't selected, none of the playlists convert and it returns the same runtime error.

Blank playlist in empty directory works just fine. Converts with no errors and converted over all 51 test tracks.

Tried some of my playlists in a blank directory. None of my original playlists will convert in batches, and all of them will only do the first 7 tracks. There are two things I wonder that might be affecting this: 1) many of my playlists are AutoLists (though my regular playlists don't work either) and 2) some of my tracks have foreign languages in them.

Which config options do you need me to list? Not quite sure what you'd need to figure out if I did something weird.

Thanks for the help!

stoffel

Re: Script to fix dumb Zen MX playlist format

Post by stoffel » Wed Sep 21, 2011 8:47 am

PawWriter wrote:Hi there,
The "one playlist at a time" error happens only when "Force relative paths" is selected. When that option isn't selected, none of the playlists convert and it returns the same runtime error.
Sure you are using the latest version of my script ??? It should run fine NOT depending on "Force relative paths" ! Tested this!!!
Please try the latest version below (with a small fix). You could post a pl example and your Scriptconfiguration:

var Config = { // All user changeable config settings go here
Language : 'en', // Set your prefered language (Currently 'en' = English, 'de' = German is supported)
DeleteOrgPl : false, // Set true if you want to delete original playlist files after conversion
ReplaceOrgPl : true, // Set true if you want to replace original playlist with converted version
Device : 'ZENMX', // Define your player device here, see 'DeviceConfig' for possible devices (ZENMX,ZENSTYLE100)
NewPlName : "@ %1.%2", // Mask for new Playlist filenames,
// %1 is replaced with old filenameprefix, %2 is replaced with old filenamesuffix
ReExclFn : /@.*\.m3u$/ // RE for Filenames to be EXCLUDED from conversion (must match 'NewPlName')
},

Code: Select all

/*
  Fix stupid ZEN MX Bug: Playlists on the ZEN MX must define their tracknames in 8.3 DOS style
  Convert every playlist '<name>.m3u' found in /playlist to '@ <name>.m3u' changing tracknames to 8.3 DOS style.
  By default original files are not changed
 
  (c) Stefan Skopnik (sskopnik(at)web(dot)de)
 
  01.01.2010 fixes for W7, don't generate if newpl exists and is newer than orgpl, changed NewPlName
  14.01.2010 scan for drive modified, test for dir exist, more detailed messages, change naming schema again to: '@ <name>.m3u'
  08.09.2011 fixes for Zen Style 100 and MM4 (now works with MM3 and MM4)
  12.09.2011 New Configsystem. New flags DeleteOrgPl and ReplaceOrgPl.
             Now you can decide if you want to:
             - delete the original pl-file after conversion (DeleteOrgPl=true) leaving only the converted @pl-file
             - replace the old pl-file with the converted version (ReplaceOrgPl=true) preserving the original name.
               (This may be the default in the future, Here only converted files are taken into account)
  18.09.2011 fix: don't create @-files of 0 bytes if no file need to be created


Installation:
-------------

1.) Copy this file to <MediaMonkeyInstallDir>\Scripts\FixZenMXPlaylist.js
    (Windows7: This dir is write protected, you have to change this!)

2.) Append to file <MediaMonkeyInstallDir>\Scripts\scripts.ini:

< --- COPY AFTER THIS LINE --->
[FixZenMXPlaylist]
FileName=FixZenMXPlaylist.js
ProcName=FixZenMXPlaylist
Order=1
DisplayName=Fix dumb ZEN MX playlist
;DisplayName=Korrektur von ZEN MX Playlisten

Description=Fixes ZEN MX playlist by converting filepath into 8.3 DOS format
;Description=Korrektur von ZEN MX Playlisten durch Konvertieren der Dateinamen/pfade in das 8.3 DOS Format
Language=JScript
ScriptType=0
<--- COPY BEFORE THIS LINE --->

3.) (Re)start MM

4.) Plugin Zen MX and create PLs in MediaMonkey

5.) Send PL to 'My ZEN'

6.) Run this Script from Extras / Scripts / Fix dumb ZEN MX playlist

7.) Unplug ZEN MX

8.) Enjoy your MM PL on ZEN MX. You find them under '@ <ORGNAME>.m3u


Configuration:
-------------

This script should work 'out of the box' with Zen MX Player using english laguage.
If you like you can configure the script in some aspects. See 'Config' for options

*/

var Config = {                              // All user changeable config settings go here
        Language     : 'en',                // Set your prefered language (Currently 'en' = English, 'de' = German is supported)
        DeleteOrgPl  : false,               // Set true if you want to delete original playlist files after conversion
        ReplaceOrgPl : true,               // Set true if you want to replace original playlist with converted version
        Device       : 'ZENMX',             // Define your player device here, see 'DeviceConfig' for possible devices (ZENMX,ZENSTYLE100)
        NewPlName    : "@ %1.%2",           // Mask for new Playlist filenames,
                                            // %1 is replaced with old filenameprefix, %2 is replaced with old filenamesuffix
        ReExclFn     : /@.*\.m3u$/          // RE for Filenames to be EXCLUDED from conversion (must match 'NewPlName')
    },
    
    re_inclfn    = /\.m3u$/,                // RE for Filenames to be INCLUDED into conversion
    re_ignoreln  = /^#/,                    // RE for lines to be ignored during conversion
    OutDrive     = "?",                     // Define your Zen MX Drive ('X:') or leave "?" to let script find device
    OutDir       = "\\Playlist",            // Define location of PL on device
    Scriptname   = "FixZenMXPlaylist.js",
    Version      = "1.05",
    FileComment  = "#!@ 8.3 DOS converted by %1 V%2",
    re_flag      = /^#!@ 8.3 DOS converted/,

    DeviceConfig = {                        // Deviceconfiguration. You have to look into the registry!
        'ZENMX'       : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_MX",
        'ZENSTYLE100' : "USBSTOR\\Disk&Ven_Creative&Prod_ZEN_Style_Series&Rev_0200"
    },

    Lang_rc = {
        'de' : {
            msg0 : "Es wurden keine Playlisten im Verzeichnis '%2' erstellt.",
            msg1 : "Folgende %1 neue Playlisten wurden im Verzeichnis '%2' erstellt:\n\n",
            msg2 : "Folgende neue Playliste wurde im Verzeichnis '%2' erstellt:\n\n",
            msg4 : "Kein Zen MX MP3-Player gefunden!",
            msg5 : "Zen MX MP3-Player in Laufwerk '%1' gefunden.\nPlaylisten konvertieren?",
            msg6 : "Unterverzeichnis '%1' auf Laufwerk '%2' nicht gefunden!",
            msg7 : "Zen MX MP3-Player gefunden, aber Unterverzeichnis '%1' fehlt!"
        },
        'en' : {
            msg0 : "No playlists created in directory '%2'.",
            msg1 : "%1 new playlists where created in directory '%2':\n\n",
            msg2 : "%1 new playlist was created in directory '%2':\n\n",
            msg4 : "No Zen MX MP3-Player found!",
            msg5 : "Found Zen MX MP3-Player in drive '%1'.\nConvert Playlists?",
            msg6 : "Subdirectory '%1' missing on drive '%2'!",
            msg7 : "Zen MX MP3-Player found, but subdirectory '%1' missing!"
        }
    },
    Lang = Lang_rc[Config.Language],
    
    objFso = new ActiveXObject("Scripting.FileSystemObject"),
    objDic = new ActiveXObject("Scripting.Dictionary"),
    C_ForReading = 1
;

// some utillity functions

function sprintf() {
var savearg = arguments;

    return savearg[0].replace(new RegExp("%(\\d+)","g"),
                function ($0, $1, $2) { return savearg[$1]; }
           );
}

function getDriveLetter(i) {
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    s;
    s = str.charAt(i);
    return(s + ":");
}

function JS2VBArray(objJSArray) {
    objDic.RemoveAll();
    for (var i = 0; i < objJSArray.length; i++ ) {
        objDic.add(i,objJSArray[i]);
    }
    return objDic.Items();
}

function getShortPath(filespec, nodrive) {
var f = objFso.GetFile(filespec),
    ret = f.ShortPath;

    if (nodrive) ret = ret.substr(2);
    return(ret);
}

function convColltoArr(col) {
var ret = new Array();

    for (var e = new Enumerator(col), i = 0; !e.atEnd(); e.moveNext(), i++) {
        ret[i] = e.item();
    }
    return ret;
}

function stripDriveLetter(fn) {
var start = fn.indexOf(":");

    return fn.slice(++start);
}

function getPath(fn) {
var stop = fn.lastIndexOf("\\");

    if (stop==-1) return "";
    return fn.slice(0,stop);
}

function getFilename(fn) {
var start = fn.lastIndexOf("\\");

    return fn.slice(++start);
}

function getFilenamePrefix(fn) {
var ret = getFilename(fn),
    stop = ret.lastIndexOf(".");

    if (stop==-1) return ret;
    return ret.slice(0,stop);
}

function getFilenameSuffix(fn) {
var ret = getFilename(fn),
    start = ret.lastIndexOf(".");

    if (start==-1) return "";
    return ret.slice(++start);
}

function messageBox(s,t,barr) {
    return SDB.MessageBox(s, t, JS2VBArray(barr));
}

// ---

function FixZenMXPlaylist() {
var fc,
    fin,
    fout,
    orgfile,
    newfile,
    newfilearr = new Array(),
    nrfiles = 0,
	bufferline,
    ret,
    devlist,
    i,
    f_org,
    f_new,
    actmsg;

    /*
     * Find the Drive letter of Zen MX
     * Well, I have no real idea what ActiveDeviceList is supposed to return. XP and W7 return complety different FriendlyNames.
     * In W7 the second Drive is never returned.
     * So this is a rather dumb method:
     *
     * Scan all Drives with correct vendor&Product Name.
     *   If you find drive with existing subdir <OutDir> use it!
     *   else give up!
     *
     * This was tested with XP / W7 successfully
     */
    if (OutDrive == "?") {
        devlist = SDB.Device.ActiveDeviceList(DeviceConfig[Config.Device]); 
        for (i = 0; i < devlist.Count;i++) {
            OutDrive = "!";
            //messageBox(i + ": (" + devlist.DeviceID(i) + ") " + devlist.FriendlyName(i) + " " +
            //    devlist.DeviceInst(i) + " " + getDriveLetter(devlist.DriveLetterIndex(i)), mtInformation, new Array(mbOk) );
            TestOutDrive = getDriveLetter(devlist.DriveLetterIndex(i));
            // if (devlist.FriendlyName(i) == "Creative ZEN MX USB Device") break;
            if (objFso.FolderExists(TestOutDrive + OutDir)) {
                OutDrive = TestOutDrive;
                break;
            }
        }
    }
    switch (OutDrive) {
        case "?":   messageBox(Lang.msg4, mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
                    return(-1);
        case "!":   messageBox(sprintf(Lang.msg7, OutDir), mtError, new Array(mbOk.toString()));
                    return(-1);
        default:    ret = messageBox(sprintf(Lang.msg5, OutDrive), mtConfirmation, new Array(mbOk, mbCancel));
                    if (ret == mrCancel) return (-2);
    }

    // Ok, we want this folder! Else exit
    if (!objFso.FolderExists(OutDrive + OutDir)) {
        messageBox(sprintf(Lang.msg6, OutDir, OutDrive), mtError, new Array(mbOk.toString())); // single num arg to array constructor sets array size!
        return(-1);
    }

    objDir = objFso.GetFolder(OutDrive + OutDir);

    for (fc = new Enumerator(objDir.files); !fc.atEnd(); fc.moveNext()) {
        ele = fc.item();
        if (re_inclfn.test(ele.Name) && !Config.ReExclFn.test(ele.Name)) {
            // WScript.Echo("File: " + ele.Path);

            orgfile = ele.Path;
            newfile = getPath(orgfile) + "\\" + sprintf (Config.NewPlName, getFilenamePrefix(orgfile), getFilenameSuffix(orgfile));

            // Don't generate if newfile already exists and is newer than oldfile
            if (objFso.FileExists(newfile)) {
                f_org = objFso.GetFile(orgfile);
                f_new = objFso.GetFile(newfile);
                if (f_new.DateLastModified > f_org.DateLastModified) continue;
            }

            fin = objFso.OpenTextFile(orgfile, C_ForReading, false);
            l = fin.ReadLine();
            if (!l || re_flag.test(l)) continue;    // was the file already converted? don't do it again
            bufferLine = l;                         // else buffer the first line

            fout = objFso.CreateTextFile(newfile, true);
            nrfiles++;
            newfilearr.push(getFilename(Config.ReplaceOrgPl ? orgfile : newfile));
            fout.WriteLine(sprintf(FileComment, Scriptname, Version)); // mark new file as converted
            while (!fin.AtEndOfStream) {

                if (bufferLine) {   
                    l = bufferLine;
                    bufferLine = undefined;
                } else {
                    l = fin.ReadLine();
                }

                if (!re_ignoreln.test(l)) {
                    l = stripDriveLetter(l);    // MM4 by default generates filepath with drive letters, we don't want them!
                    sn = getShortPath(OutDrive + l, true);
                    l = sn;
                }
                fout.WriteLine(l);

            }
            fin.Close();
            fout.Close();

            if (Config.DeleteOrgPl || Config.ReplaceOrgPl)    objFso.DeleteFile(orgfile, true);
            if (Config.ReplaceOrgPl)                          objFso.MoveFile(newfile, orgfile);
        }
    }
    switch (nrfiles) {
        case 0:     actmsg = 'msg0'; break
        case 1:     actmsg = 'msg2'; break
        default:    actmsg = 'msg1';
    }
    messageBox(sprintf(Lang[actmsg], nrfiles, OutDrive + OutDir) + newfilearr.join(", "),
        mtInformation, new Array(mbOk.toString())
    );
    return (0);
}

Post Reply