Here is another, probably last update of my script. It provides some more elaborate error handling in case of missing track files.
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)
// 24.12.2012 More intelligent error handling in case of missing files
/*
Installation:
-------------
0.) IMPORTANT: Configure your ZEN device in MM : Under Playlist / Options: *Don't* use
UTF8 Unicode Coding for .m3u playlists
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 language.
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.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!",
msg8 : "Fehler in Playliste '%1':\nFehlender Titel '%2'!\n\nAbbrechen = Weiter mit der nächsten Playliste, Abbruch = Programmabbruch",
msg9 : "Einige Titel konnten nicht gefunden werden!"
},
'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!",
msg8 : "Error in playlist '%1':\nMissing title '%2'!\n\nCancel = Continue with next playlist, Abort = Exit program",
msg9 : "Could't find some titles!"
}
},
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) {
// messageBox("File: " + filespec, mtInformation, new Array(mbOk.toString()));
var f,
ret;
try {
f = objFso.GetFile(filespec),
ret = f.ShortPath;
} catch (e) {
return undefined;
}
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,
ret2,
bIgnoreAll = false,
devlist,
i,
f_org,
f_new,
actmsg,
errmsg = '';
/*
* 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() && ret2 != mrAbort; 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)) { // was the file already converted? don't do it again
fin.Close();
fout.Close();
objFso.DeleteFile(newfile, true);
continue;
}
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) {
ret2 = undefined;
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);
if (sn == undefined) {
if (bIgnoreAll) ret = mrIgnore;
else {
errmsg = '\n\n' + Lang['msg9'];
ret2 = messageBox(sprintf(Lang['msg8'], orgfile, OutDrive + l),
mtError, new Array(mbCancel.toString(), mbAbort.toString(), mbIgnore.toString(), mbIgnoreToAll.toString() )
);
if (ret2 == mrAbort || ret2 == mrCancel) break;
if (ret2 == mrIgnoreToAll) bIgnoreAll = true;
}
}
l = sn;
}
if (ret2 == undefined) 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(", ") + errmsg,
errmsg ? mtError : mtInformation, new Array(mbOk.toString())
);
return (0);
}