﻿var script_name = "MediaInfoTip";
var script_version = "1.2.0";
var FSU = DOpus.FSUtil();
try {
	var MediaInfoPath = DOpus.Aliases('MediaInfoCLI').path + "\\MediaInfo.exe";
	if (!FSU.Exists(MediaInfoPath)) MediaInfoPath = false;
}
catch (error) {
	MediaInfoPath = false;
}

try {
	var json_template = DOpus.Aliases('MediaInfoCLI').path + '\\template.txt';
	if (!FSU.Exists(json_template)) json_template = false;
}
catch (error) {
	json_template = false;
}
var cache_dir = false;

function OnInit(ScriptInitData) {
	ScriptInitData.name = script_name;
	ScriptInitData.default_enable = true;
	ScriptInitData.version = script_version;
	ScriptInitData.min_version = "13.14";
	ScriptInitData.url = "https://resource.dopus.com/t/mediainfotip-chapters-column-and-more/47295";
	ScriptInitData.config_desc = DOpus.Create.Map();
	ScriptInitData.config.debug = DOpus.Create.Vector(1, 'ALL', 'WARNING', 'OFF');
	ScriptInitData.config_desc('debug') = "Logging level to be displayed. OFF to shows none.\nALL to shows all the messages.\nWARNING to shows error conditions that are of consideration.";
	ScriptInitData.config.cache_dir = "";
	ScriptInitData.config_desc('cache_dir') = "Path to temporary folder for store cache files";
}
// Called to add commands to Opus
function OnAddCommands(addCmdData) {
	var cmd = addCmdData.AddCommand();
	cmd.name = script_name;
	cmd.method = "MICommands";
	cmd.desc = "";
	cmd.label = script_name;
	cmd.template = "CLEARCACHE/S,BUILDTEMPLATE/S";
	cmd.hide = false;
	cmd.icon = "script";
}

function MICommands(SCD) {
	if (SCD.func.args.got_arg.clearcache) {
		if (!cache_dir) {
			try {
				cache_dir = (Script.config.cache_dir) ? FSU.Resolve(Script.config.cache_dir) : (DOpus.Aliases('MediaInfoCLI').path + "\\cache");
			}
			catch (err) {
				Log(3, "Unable to get cache folder dir!");
				return;
			}
		}
		if (!FSU.Exists(cache_dir)) return;
		if (SCD.func.Dlg().Request("This can't be undone\nReally delete " + cache_dir + " content?", "Yes|No", script_name + " - Delete Cache") == 1) {
			var cmd = DOpus.Create.Command();
			if (cmd.RunCommand('Delete "' + cache_dir + '\\*" NORECYCLE FORCE QUIET') !== 0)
				Log(1, cache_dir + " content succesfully deleted");
			else
				Log(2, cache_dir + " content couldn't be deleted");
			cmd = null;
		}
	}
	if (SCD.func.args.got_arg.buildtemplate) {
		if (!MediaInfoPath) {
			if (!setMediaInfoPath(SCD.func.sourcetab.Dlg()))
				return;
		}
		CreateTemplate(DOpus.Aliases('MediaInfoCLI').path + "\\template.txt");
	}
}

// Called to add commands to Opus
function OnAddColumns(addColData) {
	AddColumn(addColData, "video", "Info Video", "movie", true);
	AddColumn(addColData, "audio", "Info Audio", "movie", true);
	AddColumn(addColData, "subs", "Info Subs", "movie", true);
	AddColumn(addColData, "chapters", "Chapters", "movie", false, "number");
	AddColumn(addColData, "bitrate", "General Bitrate", "movie", false, "double");
	AddColumn(addColData, "profile", "Profile", "movie");
	AddColumn(addColData, "refframes", "RefFrames", "movie", false, "number");
	AddColumn(addColData, "scantype", "Scan Type", "movie");
	AddColumn(addColData, "ar", "MI AR", "movie");
	AddColumn(addColData, "fps", "MI FPS", "movie", false, "double");
	AddColumn(addColData, "frameratemode", "FR Mode", "movie");
	AddColumn(addColData, "colorspace", "Color Space", "movie");
	AddColumn(addColData, "chroma", "Chroma", "movie");
}

function GetInfo(SCD) {
	Log(1, '===========================================================');

	with(SCD) {
		if (!item || item == null) return;
		Log(1, "ITEM       : " + item + "   TYPE : " + item.metadata);

		if (!item.inGroup("name:Movies") || item.is_reparse || item.is_junction || item.is_symlink) {
			errorCols(columns, "NO INFO");
			return;
		}
		if (!MediaInfoPath) {
			Log(2, "MediaInfo.exe can't be located!");
			//Choose MediaInfo CLI path
			if (!setMediaInfoPath(tab.Dlg())) {
				errorCols(columns, "NO MEDIAINFO.exe");
				return;
			}
		}
		if (!json_template) {
			Log(2, "json_template can't be located!");
			json_template = CreateTemplate(DOpus.Aliases('MediaInfoCLI').path + "\\template.txt");
			if (!json_template) {
				errorCols(columns, "NO TEMPLATE");
				return;
			}
			Log(1, "template   : " + json_template);
		}
		if (!cache_dir) {
			cache_dir = (Script.config.cache_dir) ? FSU.Resolve(Script.config.cache_dir) : (DOpus.Aliases('MediaInfoCLI').path + "\\cache");
			if (!FSU.Exists(cache_dir)) {
				var cmd = DOpus.Create.Command();
				cmd.RunCommand('CreateFolder "' + cache_dir + '" READAUTO=no');
				cmd = null;
			}
			Log(1, "cache dir  : " + cache_dir);
		}
		var media_json = GetMediaInfo(item);
		if (!media_json) {
			Log(3, "Can't obtain json file with the neccesary info!!");
			errorCols(columns, "MEDIAINFO ERROR");
			return;
		}
		// Log(1, "RAW JSON   : " + media_json);
		try {
			var MediaInfo = JSON.parse(media_json);
		}
		catch (e) {
			Log(3, "JSON file seems invalid!!");
			errorCols(columns, "PARSE ERROR");
			return;
		}
		if (MediaInfo && typeof MediaInfo === "object") {
			var i, audio, subs, video, value;

			with(MediaInfo) {
				if (SCD.columns.Exists("bitrate")) {
					if ("General" in MediaInfo && "bitrate" in MediaInfo.General) {
						try {
							SCD.columns("bitrate").value = General.bitrate;
						}
						catch (e) {
							Log(2, "Can't read bitrate: " + e.description);
						}
					}
					else SCD.columns("bitrate").value = 0;
				}
				if ("Video" in MediaInfo) {
					if (SCD.columns.Exists("video")) {
						try {
							video = Video.infotip;
						}
						catch (e) {
							Log(2, "Can't parse video info: " + e.description);
							video = 'No';
						}
						Log(1, "VIDEO      : " + video);
						putInfo(SCD.columns("video"), video);
					}
					try {
						SCD.columns("profile").value = Video.profile;
						SCD.columns("scantype").value = Video.scantype;
						SCD.columns("refframes").value = Video.refframes;
						SCD.columns("ar").value = Video.ar;
						SCD.columns("fps").value = Video.fps;
						SCD.columns("frameratemode").value = Video.frameratemode;
						SCD.columns("colorspace").value = Video.colorspace;
						SCD.columns("chroma").value = Video.chroma;
					}
					catch (e) {
						Log(2, "Can't parse video info: " + e.description);
					}
				}
				else {
					Log(1, "VIDEO      : NO INFO");
					if (SCD.columns.Exists("video")) SCD.columns("video").value = "No";
					errorCols(columns);
				}
				if (SCD.columns.Exists("audio")) {
					if ("Audio" in MediaInfo) {
						audio = (Audio.length > 1) ? Audio.length + "\r\n" : "";
						for (i = 0; i < Audio.length; i++) {
							try {
								audio += "\t" + Audio[i].infotip;
								audio += (i < Audio.length - 1) ? "\r\n" : "";
							}
							catch (e) {
								Log(2, "Can't parse audio info: " + e.description);
								audio = 'No';
								break;
							}
						}
						Log(1, "AUDIO      : " + audio);
						putInfo(SCD.columns("audio"), audio);
					}
					else {
						Log(1, "AUDIO      : NO INFO");
						SCD.columns("audio").value = "No";
					}
				}
				if (SCD.columns.Exists("subs")) {
					if ("Subs" in MediaInfo) {
						subs = (Subs.length > 1) ? Subs.length + "\r\n" : "";
						for (i = 0; i < Subs.length; i++) {
							try {
								subs += "\t" + Subs[i].infotip;
								subs += (i < Subs.length - 1) ? "\r\n" : "";
							}
							catch (e) {
								Log(2, "Can't parse subs info: " + e.description);
								subs = 'No';
								break;
							}
						}
						Log(1, "SUBS       : " + subs);
						putInfo(SCD.columns("subs"), subs);
					}
					else {
						Log(1, "SUBS       : NO INFO");
						SCD.columns("subs").value = "No";
					}
				}
				if (SCD.columns.Exists("chapters")) {
					if ("Menu" in MediaInfo && Menu.begin && Menu.end) SCD.columns("chapters").value = Menu.end - Menu.begin;
					else SCD.columns("chapters").value = 0;
				}
			}
		}
		else errorCols(columns, "NO INFO");
	}
	MediaInfo = null;
	Log(1, "Command finished!");
	return;
}

function GetMediaInfo(file) {
	var salida = false;
	var shell = new ActiveXObject("WScript.Shell");
	var str_tools = DOpus.Create.StringTools();
	var json_logfile = FSU.GetItem(cache_dir + '\\' + str_tools.RemoveDiacritics(str_tools.MakeLegal(file.realpath, 'n')) + '.txt');
	Log(1, "JSON File  : " + json_logfile);
	if (!FSU.Exists(json_logfile) || json_logfile.modify.Compare(file.modify) != 0) {
		Log(1, "Running " + MediaInfoPath + " for " + file);
		var m = '"' + MediaInfoPath + '" --Inform=file://"' + json_template + '" --LogFile="' + json_logfile + '" "' + file.realpath + '"';
		Log(1, "cmdline    : " + m);
		try {
			shell.Run(m, 0, true);
		}
		catch (e) {
			Log(3, "Can't run MediaInfo.exe : " + e.description);
			return false;
		}
		var fs = json_logfile.Open("m");
		if (fs.error !== 0)
			Log(2, "An error occurred while setting file modify date");
		else {
			try {
				fs.SetTime(file.modify);
			}
			catch (e) {
				Log(2, "Can't set modify date as " + file.modify);
			}
			finally {
				fs.Close();
			}
		}
		fs = null;
	}
	salida = validJSON(ReadFile(json_logfile));
	shell = null;
	str_tools = null;
	return salida;
}

function putInfo(column, value) {
	if (value !== 'No') {
		value = value.replace(/ +/g, " ").replace(/(, )+/g, ", ");
	}
	column.value = value;
}

function ReadFile(filename) {
	Log(1, "Reading " + filename + " ...");
	var res = false;
	var file = filename.Open();
	if (file.error !== 0)
		Log(3, "An error occurred while opening the file");
	else {
		try {
			var blob = file.Read();
			res = DOpus.Create.StringTools.Decode(blob, "utf-8");
			blob.Free();
		}
		catch (e) {
			Log(3, "Can't read " + filename + " : " + e.description);
		}
		finally {
			file.Close();
		}
	}
	return res;
}

function validJSON(value) {
	if (!value) return false;
	return value
		.replace(/\\/g, '\\\\')
		.replace(/"/g, '\\"')
		.replace(/\n/g, '\\n')
		.replace(/\r/g, '\\r')
		.replace(/\t/g, '\\t')
		.replace(/'/g, '"');
}

function CreateTemplate(filename) {
	Log(1, "Creating template " + filename);
	var content = "File;\r\nFile_Begin;{\r\nFile_Middle;,\r\nFile_End;}\r\n";
	content += "General;'size': '%FileSize/String%','bitrate': '%OverallBitRate/String%','duration': '%Duration%','Created': '%File_Created_Date%','Modified': '%File_Modified_Date%','encoded': '%Encoded_Date%','released': '%Released_Date%','tagged': '%Tagged_Date%'\r\nGeneral_Begin;'General':{\r\nGeneral_Middle;\r\nGeneral_End;}\r\n";
	content += "Video;'infotip': '$if(%Title%,%Title%,No Title) : %Width% x %Height%, ($if(%BitRate%,Bitrate: %BitRate/String%,), $if(%DisplayAspectRatio%, AR: %DisplayAspectRatio/String%,), $if(%Format_Settings%, Settings: %Format_Settings%,) %Format/String%, $if(%ChromaSubsampling%, Chroma: %ChromaSubsampling/String%,), $if(%Format_Profile%, Profile: %Format_Profile%,) $if(%BitDepth%, at %BitDepth/String%,)) (ID: %ID/String%)','refframes': '%Format_Settings_RefFrames%','profile': $if(%Format_Profile%,'%Format_Profile%',''),";
	content += "'scantype': $if(%ScanType/String%,'%ScanType/String%',''),'frameratemode': $if(%FrameRate_Mode/String%,'%FrameRate_Mode/String%','') ,'formatinfo': $if(%Format/Info%,'%Format/Info%',''),'fps': $if(%FrameRate%,'%FrameRate%',''),'fpsfull': $if(%FrameRate/String%,'%FrameRate/String%',''),'ar': $if(%DisplayAspectRatio/String%,'%DisplayAspectRatio/String%',''),'colorspace': $if(%ColorSpace%,'%ColorSpace%',''),'chroma': $if(%ChromaSubsampling/String%,'%ChromaSubsampling/String%','')\r\nVideo_Begin;,'Video':{\r\nVideo_Middle;,\r\nVideo_End;}\r\n";
	content += "Audio;{'infotip': '$if(%Language%,%Language/String%,No Language) ($if(%Title%,%Title%,No Title)), %Duration/String%, $if(%Format%,%Format/String%,), $if(%CodecID/String%,Codec: %CodecID/String%,), $if(%BitDepth/String%,%BitDepth/String%,), $if(%BitRate/String%,%BitRate/String%,No Bitrate) $if(%BitRate_Mode%,%BitRate_Mode%,), %Channel(s)/String% $if(%ChannelPositions%,%ChannelPositions%,), %SamplingRate/String%, $if(%Default%,Principal,), $if(%Forced%,Forced,) (ID: %ID/String%)'}\r\nAudio_Begin;,'Audio':[\r\nAudio_Middle;,\r\nAudio_End;]\r\n";
	content += "Text;{'infotip': '$if(%Language%,%Language/String%,No Language) ($if(%Title%,%Title%,No Title)), $if(%Format%,%Format/String%,Sin formato), $if(%Default%,Principal,), $if(%Forced%,Forced,) (ID: %ID/String%)'}\r\nText_Begin;,'Subs':[\r\nText_Middle;, \r\nText_End;]\r\n"
	content += "Menu;'begin': '%Chapters_Pos_Begin%','end': '%Chapters_Pos_End%'\r\nMenu_Begin;,'Menu':{\r\nMenu_Middle;\r\nMenu_End;}";
	var file = FSU.OpenFile(filename, 'w');
	if (file.error != 0) return false;
	try {
		file.Write(content);
		file.Close();
	}
	catch (e) {
		Log(3, "Error while creating template " + filename);
		filename = false;
	}
	file = null;
	return filename;
}

function errorCols(columns, value) {
	for (var e = new Enumerator(columns); !e.atEnd(); e.moveNext()) {
		switch (e.item()) {
			case "video":
			case "audio":
			case "subs":
			case "colorspace":
			case "chroma":
			case "scantype":
			case "ar":
			case "fps":
			case "frameratemode":
				if (value) columns(e.item()).value = value;
				break;
			case "bitrate":
			case "profile":
			case "refframes":
			case "chapters":
				columns(e.item()).value = 0;
				break;
		}
	}
	return;
}

function Log(level, text) {
	if (level == 3 || Script.config.debug < level) {
		if (level == 1) DOpus.Output("INFO    => " + text);
		else if (level == 2) DOpus.Output("WARNING => " + text);
		else DOpus.Output("ERROR   => " + text, true);
	}
}

function OnDeleteScript(deleteScriptData) {
	Log(1, 'Uninstalling "' + script_name + '" :(...');
	var cmd = DOpus.Create().Command();
	if (DOpus.Dlg().Request('Do you want to delete the cache to the recycle bin as well (just in case)?', 'Yes|No', 'Uninstalling' + script_name) === 1) {
		try {
			var cache = Script.config.cache_dir ? FSU.Resolve(Script.config.cache_dir) : (MediaInfoPath ? (DOpus.Aliases('MediaInfoCLI').path + "\\cache") : "");
			if (FSU.Exists(cache)) cmd.RunCommand('Delete FILE="' + cache + '" QUIET FORCE RECYCLE')
		}
		catch (err) {
			Log(2, 'Unable to delete the cache!');
		}
	}
	try {
		if (FSU.Exists(json_template)) cmd.RunCommand('Delete FILE="' + json_template + '" QUIET FORCE NORECYCLE')
	}
	catch (err) {
		Log(2, 'Unable to delete the template!');
	}

	Log(1, 'Bye bye...');

}

function setMediaInfoPath(dlg) {
	var MIexe = dlg.Open(script_name + ' - Choose MediaInfo CLI exe location');
	if (MIexe.result == true && MIexe.metadata == "exe") {
		//Save Alias
		DOpus.Aliases.Add('MediaInfoCLI', FSU.Resolve(MIexe.path));
		DOpus.Aliases.Update();
		Log(1, "MediaInfo  : " + MIexe);
		MediaInfoPath = MIexe;
		return true;
	}
	else {
		Log(3, "Can't continue without MediaInfo.exe!");
		return false;
	}
}

function AddColumn(coldata_obj, name, label, category, infotip, type, justify) {
	var col = coldata_obj.AddColumn();
	col.autorefresh = false;
	col.multicol = true;
	col.name = name;
	col.method = "GetInfo";
	col.label = label;
	col.category = category;
	col.infotiponly = infotip || false;
	col.justify = justify || "right";
	col.type = type || "string";
	col.autogroup = true;
}

// Called to display an About dialog for this script
function OnAboutScript(aboutData) {
	var dlg = DOpus.Dlg();
	dlg.window = aboutData.window;
	dlg.template = "about";
	dlg.message = "\r\n\r\n";
	dlg.title = "About " + script_name + " v" + script_version;
	dlg.Create();
	dlg.Control("text").label = 'In order to use this add-in, you need to have MediaInfo CLI exe, which can be obtained from <a id="link">here</a>. ' +
		'Make sure it is the 64 bit CLI version.\nBetter to keep it in a folder not protected by UAC.\n' +
		'The first time you try to use the add-in, you will be asked for the path where you saved the exe file.';
	try {
		dlg.Control("mediainfo_path").label = MediaInfoPath ? ('<a id="link">' + DOpus.Aliases('MediaInfoCLI').path + '</a>') : "Not yet defined";
		var cache = Script.config.cache_dir ? FSU.Resolve(Script.config.cache_dir) : (MediaInfoPath ? (DOpus.Aliases('MediaInfoCLI').path + "\\cache") : "");
		dlg.Control("cache_path").label = cache ? ('<a id="link">' + cache + '</a>') : "Not yet defined";
	}
	catch (err) {
		dlg.Control("mediainfo_path").label = "Not yet defined";
		dlg.Control("cache_path").label = "Not yet defined";
	}
	dlg.Control("mediainfo_path").AutoSize();
	dlg.Control("cache_path").AutoSize();
	dlg.Show();
	while (true) {
		var msg = dlg.GetMsg();
		if (!msg.result) break;
		if (msg.event == "click" && msg.Control === "text") {
			var cmd = DOpus.Create.Command();
			cmd.RunCommand("https://mediaarea.net/es/MediaInfo/Download/Windows");
			cmd = null;
			dlg.EndDlg(0);
		}
		if (msg.event == "click" && msg.Control === "mediainfo_path") {
			var cmd = DOpus.Create.Command();
			cmd.RunCommand("Go /MediaInfoCLI NEWTAB=tofront,findexisting");
			cmd = null;
			dlg.EndDlg(0);
		}
		if (msg.event == "click" && msg.Control === "cache_path") {
			var cmd = DOpus.Create.Command();
			cmd.RunCommand('Go "' + cache + '" NEWTAB=tofront,findexisting');
			cmd = null;
			dlg.EndDlg(0);
		}
	}
	dlg = null;
	return;
}
==SCRIPT RESOURCES
<resources>
	<resource name="about" type="dialog">
		<dialog fontsize="9" height="130" lang="english" standard_buttons="ok" width="254">
			<control halign="left" height="44" name="text" resize="t" type="markuptext" width="246" x="4" y="4" />
			<control halign="left" height="8" name="title1" resize="t" title="&lt;b&gt;Current MediaInfo Path :&lt;/b&gt;" type="markuptext" width="246" x="4" y="50" />
			<control halign="left" height="8" name="title2" resize="t" title="&lt;b&gt;Current Cache Path :&lt;/b&gt;" type="markuptext" width="246" x="4" y="82" />
			<control halign="left" height="18" name="mediainfo_path" resize="t" type="markuptext" width="246" x="4" y="60" />
			<control halign="left" height="16" name="cache_path" resize="t" type="markuptext" width="246" x="4" y="94" />
		</dialog>
	</resource>
</resources>
