2

First of all, sorry if the title is not precise enough, if anyone has suggestions they are most welcome. I will explain my problem now. I have a JSON file (although here it's a javascript object), which I want to loop through. It's a subtitle file for a movie, and I would like to show the text precisely like you would expect: only at the times specified.

I am not using a video player or anything else in conjunction with this, so it will only be nodejs going through this file. I do know how I can loop through it with a simple for loop, but I am wondering how to loop through it & do so at exactly the times specified in the respective javascript objects?

 { id: '54',
    startTime: '00:03:46,572',
    endTime: '00:03:53,160',
    text: 'Hello this is a text' 
 },
 { id: '55',
    startTime: '00:03:53,160',
    endTime: '00:03:58,799',
    text: 'To be precise, the subtitle file of a movie' 
 },
George Welder
  • 3,787
  • 11
  • 39
  • 75

2 Answers2

3

First, you must parse your startTime and endTime to milliseconds.

You can just break the string using the : and , characters, and calculate the milliseconds it represents.

function parseTime(t) {
    var segments = t.split(':');
    var ms = parseInt(segments[2].split(',')[1]);
    var h = parseInt(segments[0]);
    var m = parseInt(segments[1]);
    var s = parseInt(segments[2]);
    return h * 60 * 60 * 1000 + m * 60 * 1000 + s * 1000 + ms;
}

Next, go over your array, and transform the times to milliseconds:

function convertToMs(arr) {
    for (var i = 0; i < arr.length; i++) {
        arr[i].startTime = parseTime(arr[i].startTime);
        arr[i].endTime= parseTime(arr[i].endTime);    
    }
    return arr;
}

Now, start from the first element in the array, and set a callback to the next element on each call, unless you have reached the end of the array.

function showSubtitles(arr, i) {
    setTimeout(function() {
        console.log(arr[i].text);
        setTimeout(console.clear, arr[i].endTime - arr[i].startTime); // Make the subtitle "disappear"
        i++;
        if (arr.length > i) {
            showSubtitles(arr, i);
        }
    }, i == 0 ? (arr[i].startTime) : (arr[i].startTime - arr[i-1].startTime));
}

Now using you array:

var subtitles = [{
        id: '54',
        startTime: '00:03:46,572',
        endTime: '00:03:53,160',
        text: 'Hello this is a text' 
    },
    { 
        id: '55',
        startTime: '00:03:53,160',
        endTime: '00:03:58,799',
        text: 'To be precise, the subtitle file of a movie' 
    }];
subtitles = convertToMs(subtitles);
showSubtitles(subtitles, 0);

Here is a working fiddle, with shorter subtitles timings: https://jsfiddle.net/6oxfx4s1/2/

Ron Dadon
  • 2,666
  • 1
  • 13
  • 27
  • this is an excellent answer, thanks a lot. With this answer, is there a possibility to pause the showing of subtitles & resume it again? (I know this was not my initial question, but I am wondering how I could make this fit with this solution) – George Welder Jan 17 '17 at 13:40
  • If you mean to make it "act" like a real subtitle, than sure. I've updated the answer to clear the console when the subtitle should "disappear". Also added an update to the fiddle, to show it in a div. – Ron Dadon Jan 17 '17 at 13:53
  • Oh, I did not mean that. I want to have a button which can pause going through the subtitle files, and then resume it at the time it stopped at. But I am not sure how I could implement this, or how difficult this would be. – George Welder Jan 17 '17 at 14:03
  • Not that difficult. `setTimeout` returns a handle that can be used later with `clearTimeout` to abort the future function call. So you can just keep the current handle of the next `setTimeout` call and current `i` value, and if a button is pressed then abort using `clearTimeout` and on resume start from the `i`. The problem is that you need to adjust the timings, it is possible of course, just need some more thinking (maybe keep the time passed and use it to manipulate the timings) – Ron Dadon Jan 17 '17 at 14:36
1

One solution I can think of-

Use your array of objects, set a timeout for the difference in the time between startTime and endTime.

Once the time difference in time is complete, the next object is picked up for processing or displaying(your purpose basically)

var textarr =  [{ id: '54',
    startTime: '00:03:46,572',
    endTime: '00:03:53,160',
    text: 'Hello this is a text' 
 },
 { id: '55',
    startTime: '00:03:53,160',
    endTime: '00:03:58,799',
    text: 'To be precise, the subtitle file of a movie' 
 }]

var i=0;

function getText(textarr,i){
    setTimeout(function(){
        console.log(textarr[i].text);
        i++;
        getText(textarr,i)
    },textarr[i].endTime-textarr[i].startTime) //take care of the difference of time.
}

Take care of the time difference and such minute details in code. But, this can be used for the logic.

bozzmob
  • 12,364
  • 16
  • 50
  • 73