× Attention! This tool is outdated. Consider installing the Chrome extension instead.

Import SRT file into the Originator
(Paste from Clipboard method)

(imports FNs, italics and positioning!)

Check out Export SRT


INSTRUCTIONS:

1. Your SRT file must be completely valid. No empty events. The only tags acceptable are:
<i></i> (multiple per event is OK), {\an2} (bottom position) {\an8} (top position).

2. Click the button; this will convert SRT events to Originator events, unless there is an error.

3. Press Ctrl+C (Windows) or Cmd+C (Mac) to copy the Originator events into the clipboard.

4. In the Originator there must be at least one empty event. It must be outlined in blue for the paste functionality to work.
Position your slider on the exact in-cue frame of the first event of your SRT file and press Ctrl+V (Cmd+V).

5. Tip: When pasting events from this tool into the Originator put Chrome in Offline mode so the Originator won't save a funky paste to its servers.
Review the pasted subtitles and if everything looks okay, enable internet access back. If not, simply reload, and your task won't be affected.

ALSO SEE:

Export SRT from Originator
Export MP4 from Originator (bottom of page)


Source Code


var fps = 24.00
var event_counter = 0
var new_fps = 0

function frames2tcf(framenumber,    framerate) {    //frames to timecode format 00:01:02:24
var seconds_float = framenumber / framerate           //to make it easier to calibrate FPS
var seconds_int = Math.floor(seconds_float)         //right now our best calibration technique
var seconds_frac = seconds_float - seconds_int      //is making sure the :00 frames events in Originator
var frames = Math.round(seconds_frac * framerate) + '' //export as ,000 timecode SRT
var date = new Date(0);                                    //and vice versa
date.setSeconds(seconds_int);
var timeString = date.toISOString().substr(11, 8)  
if(frames.length == 1) frames = "0"+frames    //to make sure frames count as 01, 02, etc.
var timecodef = timeString + ":" + frames
return timecodef
}

function tc2frames(timeString, framerate) {   //timecode format 00:01:02,000 to frames
    var timeArray = timeString.split(":")   
    var hours = parseInt(timeArray[0]) * 60 * 60 
    var minutes = parseInt(timeArray[1]) * 60    
    var s_ms = timeArray[2].split(",")           
    var seconds = parseInt(s_ms[0])           
    var ms = parseInt(s_ms[1])
    var totalTime = hours + minutes + seconds + ms / 1000
    var totalFrames = Math.round(totalTime * fps)
    return totalFrames
}

function uid() {   //gratefully stolen from Chrome source code
    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11)
        .replace(/[018]/g, c => (c ^ crypto.getRandomValues(
                new Uint8Array(1))[0] & 15 >> c / 4)
            .toString(16))
}

function isInt(value) { //to avoid int conversion in the main code -- we need it as string
    value = value * 1
    if (value === parseInt(value, 10)) return true
    return false
}

function setFPS() { //icky, but at least it takes almost any input and doesn't break
    var new_fps = prompt("Current FPS set to: " + fps +
        "\nPress Enter to keep current FPS or enter new, e.g. 2500 or 2397 or 2997:",
        "2400")
    if (new_fps === null) var new_fps = 2400
    new_fps = new_fps.replace(".", "")
    new_fps = new_fps.replace(",", "")
    if (new_fps.length == 2) new_fps = new_fps + "00"
    new_fps = (new_fps.substr(0, 2) + "." + new_fps.substr(2)) * 1
    if (new_fps !== fps) {
        fps = new_fps
        alert("FPS set to: " + fps)
    }
}

function stylify(text) {  //recursively returns styles: {"type":"italic", "from": INT, "to":INT AS STRING}
    var style_arr = []     //suitable for multiple tags in one event
    var styleobj = {}
    do {
        from = text.indexOf("<i>")
        text = text.replace("<i>", "")
        to = text.indexOf("</i>")
        text = text.replace("</i>", "")
        if (from !== -1 && to !== -1) {
            styleobj = {
                type: "italic"
                , from: from
                , to: to
            }
            style_arr.push(styleobj)
        }
        styleobj = {}
    } while (text.indexOf("<i>") !== -1)
    return style_arr
}

function srtPrepare() {
    var start_previous = 0
    var end_previous = 0
    var allEvents = document.getElementById('srt')
        .value.split("\n\n")
    var values = []
    setFPS()
    for (event of allEvents) {
        var style_obj = {}
        var style_arr = []
        var event_lines = event.split("\n")
        if (!isInt(event_lines[0]) || !event_lines[1].includes(
            "-->")) {
            alert("Invalid event in SRT:\n0: " + event_lines[0] +
                "\n1: " + event_lines[1] + "\nEvent: " + event)
            setTimeout(function () {
                location.reload();
            }, 3000)
            throw new Error("Invalid SRT!")
        }
        var timecode = event_lines[1].replace(/\\./g, ",")
        var start = timecode.split("-->")[0].trim()
        start = tc2frames(start)
        var end = timecode.split("-->")[1].trim()
        end = tc2frames(end)
        delta_start = start - start_previous
        delta_end = end - end_previous
        if (delta_start < 0 || delta_end <= 0 || delta_start > 7200 ||
            delta_end > 7200) {
            alert("Funky timecodes in event " + event +    //7200 is a hard-coded value
                "\n This event in-cue: " + start +         //approx 5 min max gap between events
                "; previous event in-cue: " + start_previous +  //because the Originator WILL break
                "\nThis event out-cue: " + end +              //if given a value of, say, 99999999 frames
                "; previous event out-cue: " + end_previous)
            setTimeout(function () {
                location.reload();
            }, 3000)
            throw new Error(
                "Timecodes wrong--either not sequential or too large a gap between"
                )
        }

        if (delta_start === 0) start += 2   //frame gap of 2 added automatically
        event_lines.splice(0, 2)
        var txt = event_lines.join("\n")
            .trim()
        var rgn = "bottom"
        if (txt.indexOf("{\\an8}") !== -1) {
            rgn = "top"
        }
        txt = txt.replace(/\{.an.\}/g, "")
        var styles = stylify(txt)
        txt = txt.replace(/<i>/g, "")
        txt = txt.replace(/<\/i>/g, "")
        var editedByUser = true
        var markup = []
        var annotations = {}
        var rubies = {}
        var validations = {}
        var knp = []
        var id = uid()
        var eventType = "TIMED_TEXT_EVENT"
        var subtitle = {
            id: id
            , start: start
            , end: end
            , txt: txt
            , eventType: eventType
            , rgn: rgn
            , styles: styles
            , editedByUser: editedByUser
            , markup: markup
            , annotations: annotations
            , rubies: rubies
            , validations: validations
            , knp: knp
        }
        values.push(subtitle)
        start_previous = start
        end_previous = end
        event_counter++
    }
    var result = {
        type: "CLIPBOARD_VALUES"
        , values: values
    }
    json_events = JSON.stringify(result)
    alert("Press Enter and Ctrl+C")
    document.addEventListener('copy', function (e) {
        e.clipboardData.setData('application/json',
            json_events)
        e.preventDefault()
        alert("Copied " + event_counter + " events at FPS " +
            fps)
        event_counter = 0
            location.reload();
        setTimeout(function () {
        }, 3000)
    })
}