From 0e151870d01238dac5966b7cd5b3f5dc335558f7 Mon Sep 17 00:00:00 2001 From: Sanj Date: Fri, 30 Dec 2011 04:31:23 +0530 Subject: [PATCH] toSrt, dblclick on time-code, etc. --- index.html | 7 +- js/pandora-ui.js | 280 ++++++++++++++++++++++++++++++++++++++++++++++ js/speedtrans.js | 49 ++++++-- js/staticfuncs.js | 266 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 590 insertions(+), 12 deletions(-) create mode 100644 js/pandora-ui.js create mode 100755 js/staticfuncs.js diff --git a/index.html b/index.html index ae5cf95..277b012 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,11 @@ - - + + - + + foo diff --git a/js/pandora-ui.js b/js/pandora-ui.js new file mode 100644 index 0000000..7e52916 --- /dev/null +++ b/js/pandora-ui.js @@ -0,0 +1,280 @@ +// vim: et:ts=4:sw=4:sts=4:ft=javascript + +"use strict"; + +pandora.ui.appPanel = function() { + var that = Ox.SplitPanel({ + elements: [ + { + element: pandora.$ui.mainMenu = pandora.ui.mainMenu(), + size: 20 + }, + { + element: pandora.$ui.mainPanel = pandora.ui.mainPanel() + } + ], + orientation: 'vertical' + }); + + return that; +} + +pandora.ui.mainMenu = function() { + var that = Ox.MainMenu({ + extras: [], + id: 'mainMenu', + menus: [ + { + 'id': 'speedtransMenu', + 'title': 'Speedtrans', + 'items': [ + { id: 'TestMenu1', title: 'Test Menu Item'}, + { id: 'TestMenu2', title: 'Test Menu Itemm'} + ] + + }, + { + 'id': 'fileMenu', + 'title': 'File', + 'items': [ + { id: 'openFileMenu', title: 'Open File'}, + { id: 'saveFileMenu', title: 'Save File', keyboard: 'shift control s'} + ] + } + + ] + }) + .bindKeyboard() + .bindEvent({ + click: function(data) { +// Ox.print(data); + var selected = data.id; + if (data.id == 'saveFileMenu') { + pandora.$ui.textArea.speedtrans.save(); + // speedtrans.saveFile(); + } else if (data.id == 'openFileMenu') { + pandora.$ui.textArea.speedtrans.load("/A/480p.webm"); + } + }, + key_control_shift_s: function() { + pandora.$ui.textArea.speedtrans.save(); + } + }); + + return that; +} + +pandora.ui.mainPanel = function() { + var that = Ox.SplitPanel({ + elements: [ + { + element: pandora.$ui.videoPanel = pandora.ui.videoPanel(), + size: 400, + resizable: true, + resize: [0,600] + }, + { + element: pandora.$ui.textPanel = pandora.ui.textPanel() + } + ], + orientation: 'horizontal' + }); + return that; +} + +pandora.ui.videoPanel = function() { + var that = Ox.SplitPanel({ + elements: [ + { + element: pandora.$ui.videoPlayer = pandora.ui.videoPlayer(), + size: 300 + }, + { + element: pandora.$ui.helpPanel = pandora.ui.helpPanel() + } + ], + orientation: 'vertical' + }); + return that; +} + +pandora.ui.videoPlayer = function() { + var that = Ox.VideoPlayer({ + video: '/A/480p.webm', + controlsTop: ['play', 'fullscreen', 'scale', 'position'], + controlsBottom: ['timeline'], + height: 300, + width: 400, + showControlsOnLoad: true, + duration: 35, + timeline: '/speedtrans/img/timeline16p.png', + title: 'Test Video', + enableTimeline: true, + enableKeyboard: true, + enableMouse: true, + externalControls: true +// enableTimeline: true + }); + return that; +} + +pandora.ui.helpPanel = function() { + var that = $('
').text("Help Panel"); + return that; +} + +pandora.ui.textPanel = function() { + var that = Ox.SplitPanel({ + elements: [ + { + element: pandora.$ui.textArea = pandora.ui.textArea() + }, + { + element: pandora.$ui.textToolBar = pandora.ui.textToolBar(), + size: 20 + } + ], + orientation: 'vertical' + }); + return that; +} + +pandora.ui.textArea = function() { + var that = Ox.Input({ + type: 'textarea', + width: 400, + height: 400, + changeOnKeypress: true + }); + var $video = pandora.$ui.videoPlayer; + + that.speedtrans = { + spans: [], + insertTc: function() { + var eDom = that.find("textarea").get(0); //FIXME + var scrollTop = eDom.scrollTop; + var val = that.value(); + var pos = eDom.selectionStart; + var tcNpt = ms2npt($video.options("position") * 1000); + var newVal = val.substring(0,pos) + "\n" + tcNpt + "\n" + val.substring(pos, val.length); + that.value(newVal); + that.find("textarea").focus(); //FIXME + eDom.selectionStart = pos + tcNpt.length + 2; + eDom.selectionEnd = pos + tcNpt.length + 2; + eDom.scrollTop = scrollTop + 15; + }, + isTc: function() { + var eDom = that.find("textarea").get(0); + var val = that.value(); + var pos = eDom.selectionStart; + var word = that.speedtrans.getWord(pos, val); + + if (isValidTimecode(word)) { + return npt2ms(word); + } else { + return false; + } + }, + getWord: function(pos, val) { + var c; + var i = pos; + var j = pos; + while (c != " " && c != "\n") { + if (i==0) { + i = -1; + break; + } + i--; + c = val.substring(i,i+1); + } + var firstLetter = i+1; + var d; + while (d != " " && d != "\n") { + if (j >= val.length) { + break; + } + j++; + d = val.substring(j,j+1); + } + var lastLetter = j; + var word = val.substring(firstLetter, lastLetter); + return word; + }, + toSrt: function(fmt) { + if (!fmt) var fmt = 'srt'; + var text = cleanNewlines(that.value()); + var lines = []; + lines = text.split("\n"); + var i=0; + var j=0; + var spans = this.spans = []; + while (i < lines.length) { + var l = lines[i]; + if (isValidTimecode(l.trim())) { + var tcIn = l.trim(); + var t = ""; + var thisLine = ''; + while (!isValidTimecode(thisLine.trim())) { + i++; + if (i >= lines.length) { + break; + } + thisLine = lines[i]; + if (!isValidTimecode(thisLine.trim())) { + t += thisLine + "\n"; + } + } + var tcOut = $.trim(thisLine); + spans[j] = { + tcInMs: npt2ms(tcIn), + tcOutMs: npt2ms(tcOut), + text: t, + index: j + }; + //this.spans.push(spans[j]); + j++; + } else { + i++; + } + } + this.spans = spans; + var duration = $video.options("duration"); + var srt = spansToSrt(duration, spans, fmt); + // console.log(srt); + return srt; + }, + + save: function() { + var filename = $video.options("video"); + localStorage[filename] = that.value(); + }, + load: function(filename) { + var val = localStorage[filename] || ''; + that.value(val); + } + }; + that.bindEvent({ + key_control_space: function() { + $video.options("paused", !$video.options("paused")); + that.find("textarea").focus(); //FIXME + }, + key_control_x: function() { + that.speedtrans.insertTc(); + }, + key_control_shift_s: function() { + that.speedtrans.save(); + } + }); + that.dblclick(function() { + var tc = that.speedtrans.isTc(); + if (tc) { + $video.options("position", tc / 1000); + } + }); + return that; +} + +pandora.ui.textToolBar = function() { + var that = Ox.Bar(); + return that; +} diff --git a/js/speedtrans.js b/js/speedtrans.js index 215bc23..67bb199 100644 --- a/js/speedtrans.js +++ b/js/speedtrans.js @@ -3,26 +3,57 @@ 'use strict'; (function() { - $(function() { - Ox.load({ - UI: { - theme: 'modern' //FIXME: get theme through localStorage - } - }, loadSpeedtrans); - }); + + Ox.load({ + UI: { + theme: 'modern' //FIXME: get theme through localStorage + } + }, loadSpeedtrans); function loadSpeedtrans(browserSupported) { if (!browserSupported) { alert("your browser is not supported"); return; } - initSpeedtrans(); //FIXME: actually call as Ox.App callback + window.pandora = Ox.App({url: '/api/'}).bindEvent({ + 'load': function(data) { +// console.log(data); + + Ox.extend(pandora, { + $ui: { + body: $('body'), + document: $(document), + window: $(window).resize(function() { + pandora.resizeWindow(); + }) + }, + ui: {}, + site: {}, + user: {} + + }); + pandora.resizeWindow = function() { + pandora.$ui.textArea.options({ + 'width': pandora.$ui.textPanel.width() - 20, + 'height': pandora.$ui.textPanel.height() - 40 + }); + } + var prefix = "/speedtrans/js/"; + Ox.loadFile(prefix + "pandora-ui.js", function() { + initSpeedtrans(data); + }); + } + }); + } function initSpeedtrans(data) { - + pandora.$ui.appPanel = pandora.ui.appPanel().appendTo(pandora.$ui.body); + pandora.resizeWindow(); } + })(); + diff --git a/js/staticfuncs.js b/js/staticfuncs.js new file mode 100755 index 0000000..649df63 --- /dev/null +++ b/js/staticfuncs.js @@ -0,0 +1,266 @@ +function npt2ms(npt) { + var ms = 0.0; + npt = String(npt); + var p = npt.split(':'); + for(var i=0;i 3) { + ms = ms.toString().substring(0,3); + } + ss = it % 60; + mm = ((it - ss) / 60) % 60; + hh = ((it - (mm * 60) - ss) / 3600) % 60; + npt = hh+':'+strpad(mm.toString(), '0', 2, 'left') + npt += ':'+strpad(ss.toString(), '0', 2, 'left') + npt += '.'+strpad(ms.toString(), '0', 3, 'left') + return npt; +} + + function ms2frames(ms, fmt) { + if (!fmt) var fmt = "PAL"; + var npt = ms2npt(ms); + var dotpos = npt.lastIndexOf("."); + var mmStr = npt.substring(dotpos + 1, npt.length); + var mmInt = parseInt(mmStr); + if (fmt == 'PAL') { + var frames = parseInt((mmInt / 1000) * 24); + } else if (fmt == "NTSC") { + var frames = parseInt((mmInt / 1000) * 29.97); + } + var framesTc = ''; + var joinToken = ":"; + var framesTc = npt.substring(0, dotpos ) + joinToken + frames; + return framesTc; + } + + function ms2time(ms) { + var npt = ms2npt(ms) + return npt.substr(npt.length-9, npt.length-6); + } + +function framesToNpt(timeCode) { + var frames = timeCode.substring(9, 11); + var ms = parseInt(frames) / 25 * 1000; + var ms = String(ms); + var ms = strpad(ms, '0', 3, 'right'); + var timeCodeNpt = timeCode.substring(0,8) + "." + ms; + return timeCodeNpt; + } + + +function strpad(str, pad, len, dir) { + while (str.length < len) { + if (dir == 'left') + str = pad + str; + else if (dir == 'right') + str = str + pad; + } + return str; + } + +function isValidTimecode(tc) { + var tc = $.trim(tc); + var nptRegex = new RegExp("^[0-9][0-9]?\:[0-9][0-9]\:[0-9][0-9][\.|\,|\:][0-9]?[0-9]?[0-9]?$"); + return nptRegex.test(tc);to + } + +//where filters is a JSON object, for eg. {'Video Files': '*.dv;*.ogg;*.ogv;*.ogx;*.avi;*.mov;*.mp4;*.mpeg;*.mpg;*.vob'} +function selectFile(filters) { +// netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + const nsIFilePicker = Components.interfaces.nsIFilePicker; + var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + fp.init(window, "Choose a File", nsIFilePicker.modeOpen); + //fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText); +// fp.appendFilter("Ogg Video Files", "*.ogg;*.ogv;*.ogx;"); + for (var f in filters) { + if (filters.hasOwnProperty(f)) { + fp.appendFilter(f, filters[f]); + } + } +// fp.appendFilter("All Video Files", "*.dv;*.ogg;*.ogv;*.ogx;*.avi;*.mov;*.mp4;*.mpeg;*.mpg;*.vob"); + fp.appendFilters(nsIFilePicker.filterAll); + var rv = fp.show(); + if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { + return fp; +/* + var file = fp.file; + var path = fp.file.path; + return path; +*/ + } + return false; +} + + +function mozillaSaveFile(filePath,content) +{ + if(window.Components) { + try { +// netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(filePath); + if(!file.exists()) + file.create(0,0664); + var os = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream); + var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); + out.init(file,0x20|0x02,00004,null); + os.init(out, "UTF-8", 0, 0x0000); + os.writeString(content); + //out.write(content,content.length); + os.close(); + //out.flush(); + out.close(); + return true; + } catch(ex) { + alert(ex); + return false; + } + } + return null; +} + +function mozillaSaveAs() { + const nsIFilePicker = Components.interfaces.nsIFilePicker; + var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker); + fp.init(window, "Save srt as...", Components.interfaces.nsIFilePicker.modeSave); + fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll); + var output = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + var pth = typeof(srtFilePath) != 'undefined' ? srtFilePath : filePath + ".srt"; + output.initWithPath(pth); + fp.defaultString = output.leafName; + var rv = fp.show(); + if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { + return fp.file.path; +/* + var file = fp.file; + srtFilePath = file.path; + saveSrt(srtFilePath); + return true; +*/ + } + return false; +} + +// Returns null if it can't do it, false if there's an error, or a string of the content if successful +function mozillaLoadFile(filePath) +{ + if(window.Components) { + try { +// netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(filePath); + if(!file.exists()) + return null; + var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); + inputStream.init(file,0x01,00004,null); + //var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); + //sInputStream.init(inputStream); + var charset = "UTF-8"; + const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER; + var cInputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(Components.interfaces.nsIConverterInputStream); + cInputStream.init(inputStream, charset, 1024, replacementChar); + var str = {}; + var contents = ''; + while (cInputStream.readString(4096, str) != 0) { + contents += str.value; + } + + //var contents = sInputStream.read(sInputStream.available()); + cInputStream.close(); + //sInputStream.close(); + inputStream.close(); + return contents; + } catch(ex) { + alert(ex); + return false; + } + } + return null; +} + + +function checkFileExists(filePath) { + if(window.Components) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(filePath); + if (file.exists()) { + return true; + } else { + return false; + } + } catch(ex) { + //alert("Error"); + return null; + } + } + } + +function getFileNameExt(filename) { + var dotPos = filename.lastIndexOf("."); + var ext = filename.substring(dotPos + 1, filename.length); + return ext; + } + +function getFileNameSansExt(filename) { + var dotPos = filename.lastIndexOf("."); + if (dotPos != '-1') { + var filenameSansExt = filename.substring(0,dotPos); + } else { + var filenameSansExt = filename; + } + return filenameSansExt; + } + + +function spansToSrt(duration, arr, fmt, start_no) { + if (typeof start_no == 'undefined') { + start_no = 1; + } + var srt = ''; + var srtNo = start_no; + for (var k=0; k < arr.length; k++) { + var s = arr[k]; + if (s.text.trim() == '') { + } else { + var text = s.text.trim(); + linebreaksRegex = new RegExp('\n+', "g") + text = text.replace(linebreaksRegex, "\n"); + if (!s.tcOutMs) { + s.tcOutMs = parseInt(duration * 1000); + } + if (fmt == 'srt') { + srt += srtNo + " "; + srt += "\n"; + srt += "0" + ms2npt(s.tcInMs).replace(".", ",") + " --> " + "0" + ms2npt(s.tcOutMs).replace(".", ","); + srt += "\n"; + srt += text; + srt += "\n\n"; + } + else if (fmt == 'enc') { + srt += srtNo + ms2frames(s.tcInMs) + " " + ms2frames(s.tcOutMs) + " " + text; + srt += "\n\n"; + } + srtNo++; + } + } + return srt; + } + + + +function cleanNewlines(str) { + var s = str.replace(/\r\n|\r|\n/g, '\n'); + return s; + } +