Commits

nathbot committed e6e0bbb

Réorganisation des dossiers

Comments (0)

Files changed (38)

CP_filter_inside_nathbot.js

+// Filter Inside plugin by Nathbot
+
+VSSPlugin = {
+	// ----- Plugin constant -----
+	Name : 'Too close to filter zone',
+	Description : 'Detect subtitles that are too close from a "Filter Inside Subtitle" zone.',
+	Color : 0xFF99B3, 
+	Message : 'Subtitle too close to filter zone',
+	
+	// ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+	
+	// ----- HasError method called for each subtitle during the error checking -----
+	// If there is an error on CurrentSub return a string containing the error description.
+	// Otherwise return an empty string.
+	// Don't forget that PreviousSub and NextSub can be null
+	HasError : function(CurrentSub, PreviousSub, NextSub) {
+		var subtitleContainsSceneChange = SceneChange.Contains(
+		  CurrentSub.Start - SceneChange.StartOffset,
+		  CurrentSub.Stop + SceneChange.StopOffset);
+		if (!subtitleContainsSceneChange) {
+		  return '';
+		}
+	
+		var durMS = 0;
+	
+		// Check for scene change around start time
+		// Get the scene change next to the start time
+		var scTiming1 = SceneChange.GetNext(CurrentSub.Start);//timing of the scene change
+		var scStart1 = scTiming1 - SceneChange.StartOffset;// start of the "scene change zone"
+		
+		if(CurrentSub.Start < scStart1 && scTiming1 - CurrentSub.Start < SceneChange.FilterOffset){
+			return 'on start - only '+ (scTiming1 - CurrentSub.Start) + 'ms';
+		}
+		  
+		// Check for scene change around stop time	  
+		// Get the scene change previous to the stop time
+		var scTiming2 = SceneChange.GetPrevious(CurrentSub.Stop);
+		var scEnd2 = scTiming2 + SceneChange.StopOffset;
+	
+		if(CurrentSub.Stop > scEnd2 && CurrentSub.Stop - scTiming2 < SceneChange.FilterOffset){
+			return 'on stop - only '+ (CurrentSub.Stop - scTiming2) + 'ms'
+		}
+		
+		return '';
+	}, 
+
+	FixError : function(CurrentSub, PreviousSub, NextSub) {
+		var subtitleContainsSceneChange = SceneChange.Contains(
+		  CurrentSub.Start - SceneChange.StartOffset,
+		  CurrentSub.Stop + SceneChange.StopOffset);
+		if (!subtitleContainsSceneChange) {
+		  return;
+		}
+
+		var Message = "";
+
+		var first_start = CurrentSub.Start;
+		var first_stop= CurrentSub.Stop;
+
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// compute Lavie duration
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+		
+		// Get the scene change next to the start time
+		var scTiming1 = SceneChange.GetNext(CurrentSub.Start);//timing of the scene change
+		var scStart1 = scTiming1 - SceneChange.StartOffset;// start of the "scene change zone"
+		var scEnd1 = scTiming1 + SceneChange.StopOffset;// end of the "scene change zone"
+		//if the problem is on start...
+		if(CurrentSub.Start < scStart1 && scTiming1 - CurrentSub.Start < SceneChange.FilterOffset){
+			//try to move the sub start after the scene change
+			CurrentSub.Start = scEnd1;
+			// reading speed
+			durMS = CurrentSub.Stop - CurrentSub.Start;
+			var rsMin = 5;
+			var rsMax = 35;
+			var rsX = len * 1000 / (durMS - 500);
+			var rs = Math.round(rsX*10) / 10;
+			//if the subtitle becomes TOO FAST!, cancel
+			if (rs<0 || rs >= 35) {
+				CurrentSub.Start = first_start;
+			}
+		}
+
+		// Get the scene change previous to the stop time
+		var scTiming2 = SceneChange.GetPrevious(CurrentSub.Stop);
+		var scStart2 = scTiming2 - SceneChange.StartOffset;
+		var scEnd2 = scTiming2 + SceneChange.StopOffset;
+	
+		//if the problem is on stop...
+		if(CurrentSub.Stop > scEnd2 && CurrentSub.Stop - scTiming2 < SceneChange.FilterOffset){
+			//try to move the sub end before the scene change
+			CurrentSub.Stop = scStart2;
+			// reading speed
+			durMS = CurrentSub.Stop - CurrentSub.Start;
+			var rsMin = 5;
+			var rsMax = 35;
+			var rsX = len * 1000 / (durMS - 500);
+			var rs = Math.round(rsX*10) / 10;
+			//if the subtitle becomes TOO FAST!, cancel
+			if (rs<0 || rs >= 35) {
+				CurrentSub.Stop = first_stop;
+			}
+		}
+		return;
+
+	}
+
+};
+// Anti-Blink version 2
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Anti-Blink',
+  Description : 'Detects if there are two or three subtitles inside the specified corresponding interval.\nIf there are, it means there might be a "blinking" effect that you should try to avoid.',
+  Color : 0xE5E5E5,
+  Message : 'Anti-blink alert!',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  //ParamName : { Value : 0, Unit : 'ms', Description : 'Some description' },
+  ParamInterval2Subs : { Value : 2200, Unit : 'ms', Description : 'Interval for two subtitles' },
+  ParamInterval3Subs : { Value : 5000, Unit : 'ms', Description : 'Interval for three subtitles' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    if(PreviousSub != null && NextSub != null){
+			var startFirst = PreviousSub.Start;
+			var startCurrent = CurrentSub.Start;
+			var endFinal = NextSub.Stop;
+			var total3Subs = endFinal - startFirst;
+			var total2Subs = endFinal - startCurrent;
+			
+			if(total2Subs < this.ParamInterval2Subs.Value)
+			{
+				// two subs inside the interval
+				//ScriptLog("total2Subs duration: "+total2Subs);
+				return '2 subs in '+this.ParamInterval2Subs.Value+' '+this.ParamInterval2Subs.Unit+' is too much.';
+			}
+			else if(total3Subs < this.ParamInterval3Subs.Value)
+			{
+				// three subs inside the interval
+				//ScriptLog("total3Subs duration: "+total3Subs);
+				return '3 subs in '+this.ParamInterval3Subs.Value+' '+this.ParamInterval3Subs.Unit+' is too much.';
+			} else return '';
+		} else return '';
+  }
+  /*,
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+	
+  }*/
+}
+// Case control
+// thyresias <at> gmail.com   v1.0  26 Nov 2005   www.calorifix.net
+
+var debugMode = false;
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : "Case errors",
+  Description : "Check uppercase versus punctuation.",
+  Color : 0x00FF00, // green
+  Message : "Case",
+
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    var fix = this.CheckIt(CurrentSub, PreviousSub);
+    return fix==CurrentSub.Text ? "" : ">> " + fix.replace(/[\r\n]+/gm,"|");
+  },
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    CurrentSub.Text = this.CheckIt(CurrentSub, PreviousSub);
+  },
+
+
+  CheckIt : function(CurrentSub, PreviousSub) {
+
+    var tagText = CurrentSub.Text;
+
+    // --- prepare untagged version, remember tags
+
+    // split at tags
+    var chunks = tagText.split(/<\/?\w>/g);
+
+    // get the tags
+    // tags[i] is the tag between chunks[i-1] and chunks[i]
+    var tags = new Array(chunks.length);
+    var index = chunks[0].length;
+    for (i=1; i<chunks.length; i++) {
+      tags[i] = tagText.substr(index).replace(/(<\/?\w>)(.|[\r\n])*/m, "$1");
+      index = index + tags[i].length + chunks[i].length;
+    }
+
+    // stripped version
+    var text = tagText.replace(/<\/?\w>/g, "");
+
+    // debug
+    if (debugMode) {
+      ScriptLog("");
+      ScriptLog("tagText=[" + tagText.replace(/\r\n/mg, "|"));
+      ScriptLog("   text=[" + text.replace(/\r\n/mg, "|") + "]");
+      for (i=0; i<chunks.length; i++)
+        ScriptLog("   " + i + " = " + (i>0 ? tags[i] : "") + "[" + chunks[i].replace(/\r\n/mg, "|") + "]");
+    }
+
+    // --- correct UPpercase errors like this
+
+    var re = /([A-Z��-��-�])([A-Z��-��-�]+)([a-z��-��-�]+)/mg;
+    var match = re.exec(text);
+    while (match!=null) {
+      text =
+        text.substr(0,match.index) // before the match
+        + match[1]
+        + match[2].toLowerCase()
+        + match[3]
+        + text.substr(match.index+match[0].length) // after the match
+      ;
+      match = re.exec();
+    }
+
+    // --- uppercase after . ? !, except after ... and acronyms, bypassing double quotes
+
+    re = /([^.A-Z][.?!]"?\s+"?)([a-z��-��-�])/mg;
+
+    // prepend the last characters of previous subtitle
+    var prevText = PreviousSub == null ? "" : PreviousSub.StrippedText;
+    var prevLen = prevText.length;
+    var addText = "";
+    if (prevLen==0)     addText = "aaa. ";
+    else if (prevLen<3) addText = ("aaaa").substr(prevLen) + prevText + " ";
+    else                addText = "a" + prevText.substr(prevLen-3) + " ";
+    text = addText + text;
+
+    // debug: display matches
+    if (debugMode)
+      if (re.test(text)) {
+        ScriptLog("   text=[" + text.replace(/\r\n/mg, "|") + "]");
+        ScriptLog("   >>> [" + text.replace(re, "$1{$2}").replace(/\r\n/mg, "|") + "]");
+      }
+
+    // correct uppercase
+    match = re.exec(text);
+    while (match!=null) {
+      text =
+        text.substr(0,match.index) // before the match
+        + match[1]
+        + match[2].toUpperCase()
+        + text.substr(match.index+match[0].length) // after the match
+      ;
+      match = re.exec();
+    }
+
+    // remove previous subtitle text
+    text = text.substr(addText.length);
+
+    // --- restore tags
+
+    index = chunks[0].length;
+    tagText = text.substr(0,index);
+    for (i=1; i<chunks.length; i++) {
+      tagText += tags[i] + text.substr(index, chunks[i].length);
+      index = index + chunks[i].length;
+    }
+
+    if (debugMode)
+      ScriptLog("   tagText=[" + tagText.replace(/\r\n/mg, "|") + "]");
+
+    return tagText;
+
+  }
+
+  /*
+  CheckIt : function(CurrentSub, PreviousSub) {
+
+    var subText = CurrentSub.Text;
+
+    // --- correct UPpercase errors like this
+
+    var re = /([A-Z��-��-�])([A-Z��-��-�]+)([a-z��-��-�]+)/mg;
+    var match = re.exec(subText);
+    while (match!=null) {
+      subText =
+        subText.substr(0,match.index) // before the match
+        + match[1]
+        + match[2].toLowerCase()
+        + match[3]
+        + subText.substr(match.index+match[0].length) // after the match
+      ;
+      match = re.exec();
+    }
+
+    // --- uppercase after . ? !, except after ... and acronyms, bypassing double quotes
+
+    re = /([^.A-Z][.?!]"?\s+"?)([a-z��-��-�])/mg;
+    // check versus the last characters of previous subtitle
+    if (PreviousSub == null || PreviousSub.Text.length==0)
+      subText = "aaa. " + subText;
+    else if (PreviousSub.Text.length<3)
+      subText = ("aaaa").substr(PreviousSub.Text.length) + PreviousSub.Text + " " + subText;
+    else
+      subText = "a" + PreviousSub.Text.substr(PreviousSub.Text.length-3) + " " + subText;
+
+    if (re.test(subText)) {
+      ScriptLog("");
+      ScriptLog("[" + subText + "]");
+      ScriptLog("  >>> " + subText.replace(re, "$1[$2]"));
+    }
+    else
+      ScriptLog("  >>> fail");
+
+    match = re.exec(subText);
+    while (match!=null) {
+      subText =
+        subText.substr(0,match.index) // before the match
+        + match[1]
+        + match[2].toUpperCase()
+        + subText.substr(match.index+match[0].length) // after the match
+      ;
+      match = re.exec();
+    }
+
+    subText = subText.substr(5);
+
+    // --- final result (may be unchanged)
+
+    return subText;
+
+  }
+  */
+
+}

obsolete/CP_cp_non_pertinents_nathbot.js

+// CP non pertinents
+// par Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'CP - Correction cp non pertinents',
+  Description : 'Les changements de plan entrainant un overlap sup�rieur � la dur�e standard d\'un overlap (ou la dur�e indiqu�e) se voient attribu�e le timing 00:00,000 --> 00:00,001. Apr�s avoir utilis� ce plugin, sauvegarder-fermer-relancer, pour voir le r�sultat.',
+  Color : 0x633E4B, 
+  Message : 'CP non pertinent',
+  
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMaxOverlapCP : { Value : 250, Unit : 'ms' },
+  ParamKeyFrameIdentifier : { Value : '~', Unit : '' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    if (NextSub == null) {
+      return '';
+    }
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if (OverlapInMs < (0 - this.ParamMaxOverlapCP.Value) && 
+		(CurrentSub.Text == this.ParamKeyFrameIdentifier.Value || NextSub.Text == this.ParamKeyFrameIdentifier.Value)) {
+		return (-OverlapInMs) + 'ms overlap';
+    } else {
+      return '';
+    }
+  },
+  
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if (OverlapInMs > 0 && OverlapInMs > this.ParamMinBlank.Value) {
+      return '';
+    }
+    //check which sub is the CP: left one or right one?
+    //if it is the left one...
+	if (CurrentSub.Text == this.ParamKeyFrameIdentifier.Value){
+		//if the overlap is too big, set the CP timing to zero
+		if (OverlapInMs < (0 - this.ParamMaxOverlapCP.Value)) {
+			CurrentSub.Start = 0;
+			CurrentSub.Stop = 1;
+		} else return '';
+	} else if (NextSub.Text == this.ParamKeyFrameIdentifier.Value){
+		//if the overlap is too big, set the CP timing to zero
+		if (OverlapInMs < (0 - this.ParamMaxOverlapCP.Value)) {
+			NextSub.Start = 0;
+			NextSub.Stop = 1;
+		} else return '';
+	} else return '';
+  }
+}

obsolete/CP_cp_pertinents_nathbot.js

+// CP pertinents
+// par Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'CP - Correction cp pertinents',
+  Description : 'Correction des changements de plan entrainant un overlap inf�rieur � la dur�e standard d\'un overlap.',
+  Color : 0xffe4db, 
+  Message : 'Overlap avec un CP pertinent',
+  
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMaxOverlapCP : { Value : 250, Unit : 'ms' },
+  ParamKeyFrameIdentifier : { Value : '~', Unit : '' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    if (NextSub == null) {
+      return '';
+    }
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if (OverlapInMs > 0) {
+      return '';
+    }
+    if (OverlapInMs > (0 - this.ParamMaxOverlapCP.Value) && 
+		(CurrentSub.Text == this.ParamKeyFrameIdentifier.Value || NextSub.Text == this.ParamKeyFrameIdentifier.Value)) {
+		return (-OverlapInMs) + 'ms overlap';
+    } else {
+      return '';
+    }
+  },
+  
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    if (NextSub == null) {
+      return '';
+    }
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if (OverlapInMs > 0) {
+      return '';
+    }
+    
+    //check which sub is the CP: left one or right one?
+    //if it is the left one...
+    if (CurrentSub.Text == this.ParamKeyFrameIdentifier.Value){
+		//if the overlap is too big, set the CP timing to zero
+		if (OverlapInMs > (0 - this.ParamMaxOverlapCP.Value)) {
+			// the "left sub" is a keyframe, we only modify the "right sub"
+			NextSub.Start = CurrentSub.Stop + 1;
+		} else {
+			return '';
+		}
+	} else if (NextSub.Text == this.ParamKeyFrameIdentifier.Value){
+		//if the overlap is too big, set the CP timing to zero
+		if (OverlapInMs > (0 - this.ParamMaxOverlapCP.Value)) {
+			// the "right sub" is a keyframe, we only modify the "left sub"
+			CurrentSub.Stop = NextSub.Start - 1;
+		} else return '';
+	} else return '';
+  }
+}

obsolete/CP_reset_cp_nathbot.js

+// Reset CP
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'CP - Suppression de tous les changements de plan.',
+  Color : 0xb9a492, 
+  Description : 'Donne � tous les changements de plan le timing 00:00,000 --> 00:00,001. Apr�s avoir utilis� ce plugin, sauvegarder-fermer-relancer, pour voir le r�sultat.',
+  Message : 'Changement de plan',
+  
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamKeyFrameIdentifier : { Value : '~', Unit : '' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    if (CurrentSub.Text == this.ParamKeyFrameIdentifier.Value) {
+    	return '"Fix error" to set timing to zero';
+    } else {
+    	return '';
+    }
+  },
+  
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		CurrentSub.Start = 0;
+		CurrentSub.Stop = 1;
+  }
+}

obsolete/TIME_all_to_25_2_nathbot.js

+// All to 25
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'All to 25',
+  Description : 'Sets all subs that are under 25 cps to 25',
+  Color : 0x000000,
+  Message : '"All to 25!" Current CPS is: ',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamCPS : { Value : 25, Unit : 'Char/s', Description: 'If you want to change the CPS target'},
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+    if (CharPerSec < this.ParamCPS.Value) {
+    	return (Math.round(CharPerSec) + ' ' + this.ParamCPS.Unit);
+    } else {
+    	return '';
+    }
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+	while(CharPerSec < this.ParamCPS.Value 
+		  && Duration > VSSCore.MinimumDuration){
+		CurrentSub.Stop -=1;
+		Duration = CurrentSub.Stop - CurrentSub.Start;
+		CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+	}
+  }
+}

obsolete/TIME_all_to_25_nathbot.js

+// All to 25
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'All to 25',
+  Description : 'Sets all subs that are under 25 cps to 25',
+  Color : 0x000000,
+  Message : '"All to 25!" Current CPS is: ',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamCPS : { Value : 25, Unit : 'Char/s' },
+  ParamMinLength : { Value : 1000, Unit : 'ms' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+    if (CharPerSec < this.ParamCPS.Value) {
+    	return (Math.round(CharPerSec) + ' ' + this.ParamCPS.Unit);
+    } else {
+    	return '';
+    }
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+	while(CharPerSec < this.ParamCPS.Value 
+		  && Duration > this.ParamMinLength.Value){
+		CurrentSub.Stop -=1;
+		Duration = CurrentSub.Stop - CurrentSub.Start;
+		CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+	}
+  }
+}

obsolete/TIME_below_minimum_spotting_nathbot.js

+// below minimum spotting
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Sous-titres trop courts',
+  Description : 'Une erreur est d�tect�e quand la dur�e du st est strictement inf�rieure � ParamMinDuration.',
+  Color : 0x00C437,
+  Message : 'Les sous-titres sont trop courts :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMinDuration : { Value : 1000, Unit : 'ms' },
+  ParamNbCarSmall : { Value : 7, Unit : 'car' },
+  ParamMinDurationSmall : { Value : 800, Unit : 'ms' },
+  ParamMinBlank : { Value : 120, Unit : 'ms' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+    if(CurrentSub.StrippedText.length > this.ParamNbCarSmall.Value){
+		if (Duration < this.ParamMinDuration.Value) {
+			return (Duration + ' ' + this.ParamMinDuration.Unit);
+		} else {
+			return '';
+		}
+	} else {
+		if (Duration < this.ParamMinDurationSmall.Value) {
+			return (Duration + ' ' + this.ParamMinDurationSmall.Unit+ ' - small');
+		} else {
+			return '';
+		}
+	}
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+	Duration = CurrentSub.Stop - CurrentSub.Start;
+    if(CurrentSub.StrippedText.length > this.ParamNbCarSmall.Value){
+		CurrentSub.Stop = CurrentSub.Stop + (this.ParamMinDuration.Value - Duration); 
+    } else {
+		CurrentSub.Stop = CurrentSub.Stop + (this.ParamMinDurationSmall.Value - Duration); 
+    }
+    if (NextSub == null) {
+      return '';
+    }
+    if(NextSub.Start < CurrentSub.Stop){
+		CurrentSub.Stop = NextSub.Start - this.ParamMinBlank.Value;
+    }		
+  }
+}

obsolete/TIME_cps_too_low_old_nathbot.js

+// too slow
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Sous-titres TOO SLOW',
+  Description : 'D�tecte et corrige les sous-titres TOO SLOW. \nLevel 1 = TOO SLOW, 2 = TOO SLOW + "Slow, acceptable", 3 = TOO SLOW + "Slow, acceptable" + "A bit slow"',
+  Color : 0xE7B8FF,
+  Message : 'Vitesse :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamIdealReadingSpeed: { Value : 20, Unit : 'Char/s' },
+  ParamMinDuration: { Value : 1000, Unit : 'ms' },
+  ParamLevel : { Value : 1, Unit : '' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current length, duration
+    var len = CurrentSub.StrippedText.length;
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var dsMin = 4;
+    var dsMax = 22;
+    var dsX = len * 1000 / durMS;       // exact
+    var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+    // reading speed
+    var rsMin = 5;
+    var rsMax = 35;
+    var rsX = len * 1000 / (durMS - 500);
+    var rs = Math.round(rsX*10) / 10;
+    // rating
+    var rating;
+    if (rs < rsMin)   rating = "TOO SLOW!";
+    else if (rs < 10) rating = "Slow, acceptable.";
+    else if (rs < 13) rating = "A bit slow.";
+    else if (rs < 15) rating = "Good.";
+    else if (rs < 23) rating = "Perfect.";
+    else if (rs < 27) rating = "Good.";
+    else if (rs < 31) rating = "A bit fast.";
+    else if (rs < 35) rating = "Fast, acceptable.";
+    else              rating = "TOO FAST!";
+
+	// compute Lavie duration
+    var durLavie = 0.5 + len / this.ParamIdealReadingSpeed.Value;
+    durLavie = Math.round(durLavie*10) / 10;
+
+	//level
+	switch(this.ParamLevel.Value){
+		//3 = TOO SLOW + "Slow, acceptable" + "A bit slow"
+		case 3:
+			if (rs < 13 && rs > 0) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO SLOW + "Slow, acceptable"
+		case 2:
+			if (rs < 10 && rs > 0) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO SLOW
+		case 1:
+			if (rs < rsMin && rs > 0) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var durLavie = 0.5 + len / this.ParamIdealReadingSpeed.Value;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		while(dur > durLavie && durMS > this.ParamMinDuration.Value){
+			CurrentSub.Stop --; 	
+			durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+			dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		}
+	}
+}

obsolete/TIME_extend_cps_nathbot.js

+// Extend CPS
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Extend CPS',
+  Description : 'An error is detected when the number of Char/s is strictly '+
+  	'superior to the specified value. The fixer will extend the duration of the subtitle without overlapping the next one.',
+  Color : 0xC91191,
+  Message : 'Subtitle CPS is too fast:',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMaxCPS : { Value : 25, Unit : 'Char/s' },
+  ParamExtendToCPS : { Value : 20, Unit : 'Char/s' },
+  ParamMinBlank : { Value : 120, Unit : 'ms' },
+  ParamMaxStartMove : { Value : 250, Unit : 'ms', Description : 'D�calage maximum du d�but du sous-titre s\'il n\'y a pas assez de place pour d�caler la fin'  },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+    if (CharPerSec > this.ParamMaxCPS.Value) {
+    	return (Math.round(CharPerSec) + ' ' + this.ParamMaxCPS.Unit);
+    } else {
+    	return '';
+    }
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+		// not the last sub...
+		if(NextSub != null){
+			while(CharPerSec > this.ParamExtendToCPS.Value 
+				  && (NextSub.Start - CurrentSub.Stop) > this.ParamMinBlank.Value){
+				CurrentSub.Stop +=1; 	
+				Duration = CurrentSub.Stop - CurrentSub.Start;
+				CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+			}
+			//move the sub start if necessary
+			if(CharPerSec > this.ParamExtendToCPS.Value){
+				var totalMoved = 0;
+				while(CharPerSec > this.ParamExtendToCPS.Value
+				  && (CurrentSub.Start - PreviousSub.Stop) > this.ParamMinBlank.Value
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					Duration = CurrentSub.Stop - CurrentSub.Start;
+					CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+				}
+			}
+		}
+		// last sub...
+		else {
+			while(CharPerSec > this.ParamExtendToCPS.Value){
+				CurrentSub.Stop +=1; 	
+				Duration = CurrentSub.Stop - CurrentSub.Start;
+				CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+			}
+			//move the sub start if necessary
+			if(CharPerSec > this.ParamExtendToCPS.Value){
+				var totalMoved = 0;
+				while(CharPerSec > this.ParamExtendToCPS.Value
+				  && (CurrentSub.Start - PreviousSub.Stop) > this.ParamMinBlank.Value
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					Duration = CurrentSub.Stop - CurrentSub.Start;
+					CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+				}
+			}
+		}
+    if (NextSub == null) {
+      return '';
+    }
+  }
+}

obsolete/TIME_overlapping2_nathbot.js

+// Overlapping
+// (christophe.paris <at> free.fr)
+// extended by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Overlapping & minimum blank 2',
+  Description : 'D�tecte les overlaps et les blancs trop petits. Mode 1- d�cale �quitablement le ST pr�c�dant et le ST suivant le blanc. 2- ne d�cale que le ST pr�c�dent le blanc. 3- ne d�cale que le ST suivant le blanc.',
+  Color : 0xFF3737, 
+  Message : 'Subtitle overlap on next subtitle :',
+  
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  //ParamFixableOverlap : { Value : 100, Unit : 'ms' },
+  ParamMinBlank : { Value : 120, Unit : 'ms' },
+  ParamMode : { Value : 2, Unit : '(1/2/3)' },
+  ParamIgnoreCP : { Value : 1, Unit : '(0/1)' },
+  ParamCPidentifier : { Value : '~', Unit : '' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    if (NextSub == null) {
+      return '';
+    }
+    // ignorer changements de plans...
+    if(this.ParamIgnoreCP.Value == 1){
+		if(CurrentSub.Text == this.ParamCPidentifier.Value
+		|| NextSub.Text == this.ParamCPidentifier.Value) return '';
+    }
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if ((OverlapInMs > 0) && (OverlapInMs >= this.ParamMinBlank.Value)) {
+      return '';
+    }
+    if (OverlapInMs < 0) {
+      return (-OverlapInMs) + 'ms overlap';
+    }
+    return 'blank is only ' + OverlapInMs + 'ms';
+  },
+  
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    if (NextSub == null) {
+      return '';
+    }
+    var OverlapInMs = NextSub.Start - CurrentSub.Stop;
+    if (OverlapInMs > 0 && OverlapInMs > this.ParamMinBlank.Value) {
+      return '';
+    }
+    switch(this.ParamMode.Value){
+		case 1:
+			// Fix the overlap by dividing it by 2
+			var MiddlePoint = (CurrentSub.Stop + (OverlapInMs / 2))
+			var HalfOffset = (this.ParamMinBlank.Value / 2);
+			CurrentSub.Stop = MiddlePoint - HalfOffset;
+			NextSub.Start = CurrentSub.Stop + this.ParamMinBlank.Value;
+		break;
+		
+		case 2:
+			// d�caler uniquement le ST pr�c�dent le blanc
+			var Required = this.ParamMinBlank.Value - OverlapInMs;
+			CurrentSub.Stop -= Required;
+		break;
+		
+		case 3:
+			//d�caler uniquement le ST suivant le blanc
+			var Required = this.ParamMinBlank.Value - OverlapInMs;
+			NextSub.Start += Required;
+		break;
+	}
+  }
+}

obsolete/TIME_too_fast2_nathbot.js

+// too fast
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'TOO FAST subtitle',
+  Description : 'Detects and fixes fast subtitles so they reach the "perfect" speed',
+  Color : 0xFFA884,
+  Message : 'Speed :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  //ParamIdealReadingSpeed: { Value : 20, Unit : 'Char/s' },
+  ParamLevel : { Value : 1, Unit : '(1/2/3/4)', Description: 'Level 1 = "TOO FAST" only, 2 = "TOO FAST" + "Fast, acceptable", 3 = from "TOO FAST" to "A bit fast", 4 = from "good" to "TOO FAST"'},
+  ParamMaxStartMove : { Value : 250, Unit : 'ms', Description : 'Maximum delay of the subtitle start if there is not enough space to delay the subtitle end' },
+  ParamTryOverSC : { Value : 0, Unit : '0/1', Description : 'When set to 1: if the reading speed is still not perfect, try to move the sub end after the scene change. If it\'s still not enough, cancel' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current length, duration
+    var len = CurrentSub.StrippedText.length;
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var dsMin = 4;
+    var dsMax = 22;
+    var dsX = len * 1000 / durMS;       // exact
+    var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+    // reading speed
+    var rsMin = 5;
+    var rsMax = 35;
+    var rsX = len * 1000 / (durMS - 500);
+    var rs = Math.round(rsX*10) / 10;
+    // rating
+    var rating;
+    if (rs < rsMin && rs>0)   rating = "TOO SLOW!";
+    else if (rs < 10 && rs>0) rating = "Slow, acceptable.";
+    else if (rs < 13 && rs>0) rating = "A bit slow.";
+    else if (rs < 15 && rs>0) rating = "Good.";
+    else if (rs < 23 && rs>0) rating = "Perfect.";
+    else if (rs < 27 && rs>0) rating = "Good.";
+    else if (rs < 31 && rs>0) rating = "A bit fast.";
+    else if (rs < 35 && rs>0) rating = "Fast, acceptable.";
+    else              rating = "TOO FAST!";
+
+	// compute Lavie duration
+    var ParamIdealReadingSpeed = 20;
+    var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+    durLavie = Math.round(durLavie*10) / 10;
+
+	//level
+	switch(this.ParamLevel.Value){
+		//4 = TOO FAST + "Fast, acceptable" + "A bit fast" + "good"
+		case 4:
+			if (rs<0 || (rs >= 23 && rs < 27) || (rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//3 = TOO FAST + "Fast, acceptable" + "A bit fast"
+		case 3:
+			if (rs<0 || (rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO FAST + "Fast, acceptable"
+		case 2:
+			if (rs<0 || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO FAST
+		default:
+			if (rs<0 || rs >= 35) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		var scTiming = SceneChange.GetNext(CurrentSub.Stop);
+		var totalCPStart = scTiming - SceneChange.StartOffset;
+		var totalCPEnd = scTiming + SceneChange.StopOffset
+		// not the last sub...
+		if(NextSub != null){
+			while(dur < durLavie 
+				  && (NextSub.Start - CurrentSub.Stop) > VSSCore.MinimumBlank
+				  && CurrentSub.Stop < (totalCPStart-1)){
+				CurrentSub.Stop ++; 	
+				durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+				dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+			}
+			
+			if(PreviousSub != null){
+				//move the sub start if necessary
+				if(dur < durLavie){
+					var scTiming2 = SceneChange.GetPrevious(CurrentSub.Start);
+					var totalCPStart2 = scTiming2 - SceneChange.StartOffset;
+					var totalCPEnd2 = scTiming2 + SceneChange.StopOffset
+					var totalMoved = 0;
+					while(dur < durLavie 
+					  && (CurrentSub.Start - PreviousSub.Stop) > VSSCore.MinimumBlank
+					  && CurrentSub.Start > (totalCPEnd2+1)
+					  && totalMoved <= this.ParamMaxStartMove.Value){
+						CurrentSub.Start --;
+						totalMoved ++;
+						durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+						dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+					}
+					//if the reading speed is still not perfect, we check if it's possible to move the sub end after a scene change
+					if(this.ParamTryOverSC.Value == 1){
+						if(dur < durLavie
+							&& (NextSub.Start-CurrentSub.Stop) > VSSCore.MinimumBlank
+							&& (NextSub.Start-CurrentSub.Stop) > (SceneChange.StartOffset+SceneChange.StopOffset+SceneChange.FilterOffset)){
+							var _backupStop = CurrentSub.Stop;
+							CurrentSub.Stop += (SceneChange.StartOffset+SceneChange.StopOffset+SceneChange.FilterOffset);
+							dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit		
+							while(dur < durLavie 
+								  && (NextSub.Start - CurrentSub.Stop) > VSSCore.MinimumBlank){
+								CurrentSub.Stop ++; 	
+								durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+								dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+							}
+							dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit	
+							//if it's still not enough, we cancel this
+							if(dur < durLavie){
+								CurrentSub.Stop = _backupStop;
+							}	
+						}
+					}
+				}
+			} else {
+			//first sub...
+			//move the sub start if necessary
+			if(dur < durLavie){
+				var scTiming2 = SceneChange.GetPrevious(CurrentSub.Start);
+				var totalCPStart2 = scTiming2 - SceneChange.StartOffset;
+				var totalCPEnd2 = scTiming2 + SceneChange.StopOffset
+				var totalMoved = 0;
+				while(dur < durLavie 
+				  && CurrentSub.Start > (totalCPEnd2+1)
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+				}
+			}
+			//if the reading speed is still not perfect, we check if it's possible to move the sub end after a scene change
+			if(this.ParamTryOverSC.Value == 1){
+				if(dur < durLavie
+					&& (NextSub.Start-CurrentSub.Stop) > VSSCore.MinimumBlank
+					&& (NextSub.Start-CurrentSub.Stop) > (SceneChange.StartOffset+SceneChange.StopOffset+SceneChange.FilterOffset)){
+					var _backupStop = CurrentSub.Stop;
+					CurrentSub.Stop += (SceneChange.StartOffset+SceneChange.StopOffset+SceneChange.FilterOffset);
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit		
+					while(dur < durLavie 
+						  && (NextSub.Start - CurrentSub.Stop) > VSSCore.MinimumBlank){
+						CurrentSub.Stop ++; 	
+						durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+						dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+					}
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit	
+					//if it's still not enough, we cancel this
+					if(dur < durLavie){
+						CurrentSub.Stop = _backupStop;
+					}	
+				}
+			}
+		}
+		}
+		// last sub...
+		else {
+			while(dur < durLavie && CurrentSub.Stop < (totalCPStart-1)){
+				CurrentSub.Stop ++; 	
+				durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+				dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+			}
+			//move the sub start if necessary
+			if(dur < durLavie){
+				var scTiming2 = SceneChange.GetPrevious(CurrentSub.Start);
+				var totalCPStart2 = scTiming2 - SceneChange.StartOffset;
+				var totalCPEnd2 = scTiming2 + SceneChange.StopOffset
+				var totalMoved = 0;
+				while(dur < durLavie 
+				  && (CurrentSub.Start - PreviousSub.Stop) > VSSCore.MinimumBlank
+				  && CurrentSub.Start > (totalCPEnd2+1)
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+				}
+			}
+			
+			//if the reading speed is still not perfect, we check if it's possible to move the sub end after a scene change
+			if(this.ParamTryOverSC.Value == 1){
+				if(dur < durLavie){
+					var _backupStop = CurrentSub.Stop;
+					CurrentSub.Stop += (SceneChange.StartOffset+SceneChange.StopOffset+SceneChange.FilterOffset);
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit		
+					while(dur < durLavie){
+						CurrentSub.Stop ++; 	
+						durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+						dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+					}
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit	
+					//if it's still not enough, we cancel this
+					if(dur < durLavie){
+						CurrentSub.Stop = _backupStop;
+					}	
+				}
+			}
+		}
+	}
+}

obsolete/TIME_too_fast_nathbot.js

+// too fast
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Sous-titres TOO FAST',
+  Description : 'D�tecte et corrige les sous-titres TOO FAST. \nLevel 1 = TOO FAST, 2 = TOO FAST + "Fast, acceptable", 3 = TOO FAST + "Fast, acceptable" + "A bit fast", 4 = de "good" � "TOO FAST"',
+  Color : 0xFFA884,
+  Message : 'Vitesse :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamIdealReadingSpeed: { Value : 20, Unit : 'Char/s' },
+  ParamMinBlank : { Value : 120, Unit : 'ms' },
+  ParamLevel : { Value : 1, Unit : '1/2/3/4' },
+  ParamMaxStartMove : { Value : 250, Unit : 'ms', Description : 'D�calage maximum du d�but du sous-titre s\'il n\'y a pas assez de place pour d�caler la fin' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current length, duration
+    var len = CurrentSub.StrippedText.length;
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var dsMin = 4;
+    var dsMax = 22;
+    var dsX = len * 1000 / durMS;       // exact
+    var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+    // reading speed
+    var rsMin = 5;
+    var rsMax = 35;
+    var rsX = len * 1000 / (durMS - 500);
+    var rs = Math.round(rsX*10) / 10;
+    // rating
+    var rating;
+    if (rs < rsMin)   rating = "TOO SLOW!";
+    else if (rs < 10) rating = "Slow, acceptable.";
+    else if (rs < 13) rating = "A bit slow.";
+    else if (rs < 15) rating = "Good.";
+    else if (rs < 23) rating = "Perfect.";
+    else if (rs < 27) rating = "Good.";
+    else if (rs < 31) rating = "A bit fast.";
+    else if (rs < 35) rating = "Fast, acceptable.";
+    else              rating = "TOO FAST!";
+
+	// compute Lavie duration
+    var durLavie = 0.5 + len / this.ParamIdealReadingSpeed.Value;
+    durLavie = Math.round(durLavie*10) / 10;
+
+	//level
+	switch(this.ParamLevel.Value){
+		//4 = TOO FAST + "Fast, acceptable" + "A bit fast" + "good"
+		case 4:
+			if ((rs >= 23 && rs < 27) || (rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//3 = TOO FAST + "Fast, acceptable" + "A bit fast"
+		case 3:
+			if ((rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO FAST + "Fast, acceptable"
+		case 2:
+			if ((rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO FAST
+		default:
+			if (rs >= 35) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var durLavie = 0.5 + len / this.ParamIdealReadingSpeed.Value;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		// not the last sub...
+		if(NextSub != null){
+			while(dur < durLavie 
+				  && (NextSub.Start - CurrentSub.Stop) > this.ParamMinBlank.Value){
+				CurrentSub.Stop ++; 	
+				durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+				dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+			}
+			//move the sub start if necessary
+			if(dur < durLavie){
+				var totalMoved = 0;
+				while(dur < durLavie 
+				  && (CurrentSub.Start - PreviousSub.Stop) > this.ParamMinBlank.Value
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+				}
+			}
+		}
+		// last sub...
+		else {
+			while(dur < durLavie){
+				CurrentSub.Stop ++; 	
+				durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+				dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+			}
+			//move the sub start if necessary
+			if(dur < durLavie){
+				var totalMoved = 0;
+				while(dur < durLavie 
+				  && (CurrentSub.Start - PreviousSub.Stop) > this.ParamMinBlank.Value
+				  && totalMoved <= this.ParamMaxStartMove.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+				}
+			}
+		}
+	}
+}

obsolete/TIME_too_slow_nathbot.js

+// too slow
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Sous-titres TOO SLOW',
+  Description : 'D�tecte et corrige les sous-titres TOO SLOW. \nLevel 1 = TOO SLOW, 2 = TOO SLOW + "Slow, acceptable", 3 = TOO SLOW + "Slow, acceptable" + "A bit slow"',
+  Color : 0xE7B8FF,
+  Message : 'Vitesse :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  //ParamIdealReadingSpeed: { Value : 20, Unit : 'Char/s' },
+  ParamMinDuration: { Value : 1000, Unit : 'ms' },
+  ParamLevel : { Value : 1, Unit : '' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current length, duration
+    var len = CurrentSub.StrippedText.length;
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var dsMin = 4;
+    var dsMax = 22;
+    var dsX = len * 1000 / durMS;       // exact
+    var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+    // reading speed
+    var rsMin = 5;
+    var rsMax = 35;
+    var rsX = len * 1000 / (durMS - 500);
+    var rs = Math.round(rsX*10) / 10;
+    // rating
+    var rating;
+    if (rs < rsMin)   rating = "TOO SLOW!";
+    else if (rs < 10) rating = "Slow, acceptable.";
+    else if (rs < 13) rating = "A bit slow.";
+    else if (rs < 15) rating = "Good.";
+    else if (rs < 23) rating = "Perfect.";
+    else if (rs < 27) rating = "Good.";
+    else if (rs < 31) rating = "A bit fast.";
+    else if (rs < 35) rating = "Fast, acceptable.";
+    else              rating = "TOO FAST!";
+
+	// compute Lavie duration
+    var ParamIdealReadingSpeed = 20;
+    var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+    durLavie = Math.round(durLavie*10) / 10;
+
+	//level
+	switch(this.ParamLevel.Value){
+		//3 = TOO SLOW + "Slow, acceptable" + "A bit slow"
+		case 3:
+			if (rs < 13) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO SLOW + "Slow, acceptable"
+		case 2:
+			if (rs < 10) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO SLOW
+		default:
+			if (rs < rsMin) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		while(dur > durLavie && durMS > this.ParamMinDuration.Value){
+			CurrentSub.Stop --; 	
+			durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+			dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		}
+	}
+}

obsolete/TOO_FAST.js

+// TOO FAST
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'TOO FAST subtitles',
+  Description : 'Detects and fixes fast subtitles so they reach the "perfect" speed',
+  Color : 0xFFA884,
+  Message : 'Speed :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  //ParamIdealReadingSpeed: { Value : 20, Unit : 'Char/s' },
+  ParamLevel : { Value : 1, Unit : '(1/2/3/4)', Description: 'Level 1 = "TOO FAST" only, 2 = "TOO FAST" + "Fast, acceptable", 3 = from "TOO FAST" to "A bit fast", 4 = from "good" to "TOO FAST"'},
+  ParamMaxStartMove : { Value : 0, Unit : 'ms', Description : 'Maximum delay of the subtitle start if there is not enough space to delay the subtitle end' },
+  ParamMaxDuration : { Value : 3999, Unit : 'ms', Description : 'Maximum duration of the subtitle' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current duration
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var ds = this.CalculateDisplaySpeed(CurrentSub);
+    // reading speed
+    var rs = this.CalculateRS(CurrentSub);
+    // rating
+    var rating = this.getLabel(rs);
+
+	// compute Lavie duration
+	var durLavie = this.CalculateDurLavie(CurrentSub);
+
+	//level
+	switch(this.ParamLevel.Value){
+		//4 = TOO FAST + "Fast, acceptable" + "A bit fast" + "good"
+		case 4:
+			if (rs<0 || (rs >= 23 && rs < 27) || (rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//3 = TOO FAST + "Fast, acceptable" + "A bit fast"
+		case 3:
+			if (rs<0 || (rs >= 27 && rs < 31) || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO FAST + "Fast, acceptable"
+		case 2:
+			if (rs<0 || (rs >= 31 && rs < 35) || (rs >= 35)) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO FAST
+		default:
+			if (rs<0 || rs >= 35) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// reading speed
+		var rs = this.CalculateRS(CurrentSub);
+		var startingRS = rs;
+		var startingLabel = this.getLabel(startingRS);
+		// compute Lavie duration
+		var durLavie = this.CalculateDurLavie(CurrentSub);
+
+		var scTiming = SceneChange.GetNext(CurrentSub.Stop);
+		var totalCPStart = scTiming - SceneChange.StartOffset;
+		var totalCPEnd = scTiming + SceneChange.StopOffset
+		
+		var _backupStart = CurrentSub.Start;
+		var _backupStop = CurrentSub.Stop;
+		
+		var nextNull = 0;
+		if(NextSub == null){
+			nextNull = 1;
+		}	
+		var previousNull = 0;
+		if(PreviousSub == null){
+			previousNull = 1;
+		}		
+		// STEP 1, try to extend to perfect
+		
+			
+		// try to extend the subtitle until Perfect - only the END
+		while(dur < durLavie 
+			  && (nextNull==1 || (NextSub.Start - CurrentSub.Stop) > VSSCore.MinimumBlank)
+			  && CurrentSub.Stop < (totalCPStart-1)
+			  && durMS < this.ParamMaxDuration.Value){
+			CurrentSub.Stop ++; 	
+			durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+			dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		}
+		
+			
+			// now, the point is to get rid of the TOO FAST (not necessarily to get Perfect).
+			// so, if we're still in TOO FAST,
+			// try to move the subtitle START using the MaxStartMove value.
+			// if it respects scene changes and removes the TOO FAST, we keep this change.
+			// else, we cancel the change.
+			
+			// if we're still in TOO FAST, and if there is a scene change after the end of the subtitle,
+			// we calculate the duration with which we can extend the subtitle END.
+			// if this duration is greater than the "Filter Inside Subtitle" value,
+			// we extend the subtitle.
+			// if not, we don't do anything and the subtitler will have to improve the subtitle text.
+			
+			if(dur < durLavie){
+				// STEP 2: try to move the sub START...
+				var scTiming2 = SceneChange.GetPrevious(CurrentSub.Start);
+				var totalCPStart2 = scTiming2 - SceneChange.StartOffset;
+				var totalCPEnd2 = scTiming2 + SceneChange.StopOffset;
+				var totalMoved = 0;
+				
+				while(dur < durLavie 
+				  && (previousNull == 1 || (CurrentSub.Start - PreviousSub.Stop) > VSSCore.MinimumBlank)
+				  && CurrentSub.Start > (totalCPEnd2+1)
+				  && totalMoved <= this.ParamMaxStartMove.Value
+				  && durMS < this.ParamMaxDuration.Value){
+					CurrentSub.Start --;
+					totalMoved ++;
+					durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+					dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit					
+				}	
+				rs = this.CalculateRS(CurrentSub);
+				var rating = this.getLabel(rs);
+				//ScriptLog('rating='+rating+' rs='+rs);
+
+				
+					
+				//if the reading speed is not improved, cancel the change
+					if(startingLabel==rating){
+						CurrentSub.Start = _backupStart;
+						
+						if(this.ParamLevel.Value == 1)
+						{
+						
+							// STEP 3
+							var _backupStop2 = CurrentSub.Stop;
+					
+							// now, let's calculate the duration with which we can extend the subtitle END.
+							var isThereSC = 0;
+							var isThereSub = 0;
+							
+							var scTimingB = SceneChange.GetNext(CurrentSub.Stop);
+							var totalCPStartB = scTimingB - SceneChange.StartOffset;
+							var totalCPEndB = scTimingB + SceneChange.StopOffset;
+							
+							if(totalCPStartB == CurrentSub.Stop || totalCPStartB == CurrentSub.Stop+1){
+								// this is a scene change right next to the subtitle.
+								isThereSC = 1;
+							} else if (!nextNull && NextSub.Start - CurrentSub.Stop == VSSCore.MinimumBlank){
+								// there's a subtitle right after
+								isThereSub = 1;
+							}
+							
+							if(isThereSC == 1){
+								minimumTiming = scTimingB + SceneChange.FilterOffset + 1;
+								//if the minimum duration doesn't overlap the next minimum blank/subtitle...
+								if(nextNull == 1 || (minimumTiming < (NextSub.Start-VSSCore.MinimumBlank))){
+									CurrentSub.Stop = minimumTiming;
+									var rs = this.CalculateRS(CurrentSub);
+									
+									var scTimingC = SceneChange.GetNext(CurrentSub.Stop);
+									var totalCPStartC = scTimingC - SceneChange.StartOffset;
+									var totalCPEndC = scTimingC + SceneChange.StopOffset;
+									// now try to extend to perfect
+									while(dur < durLavie 
+										  && (nextNull==1 || (NextSub.Start - CurrentSub.Stop) > VSSCore.MinimumBlank)
+										  && CurrentSub.Stop < (totalCPStartC-1)
+										  && durMS < this.ParamMaxDuration.Value){
+										CurrentSub.Stop ++;
+										durMS = CurrentSub.Stop - CurrentSub.Start;
+										dur = Math.round(durMS/100) / 10;	
+									}
+									//if the reading speed is still TOO FAST, cancel the change
+									rs = this.CalculateRS(CurrentSub);
+									if(rs < 0 || rs >= 35){
+										CurrentSub.Stop = _backupStop2;
+									}
+								}
+							//ScriptLog('isThereSC='+isThereSC+' totalCPStartB='+totalCPStartB+' CurrentSub.Stop='+CurrentSub.Stop+' minimumTiming='+minimumTiming);
+							}
+						}
+					}
+				
+			}
+		},
+
+	CalculateRS : function (Subtitle){
+		var durMS = Subtitle.Stop - Subtitle.Start;
+		var rsX = Subtitle.StrippedText.length * 1000 / (Subtitle.Stop - Subtitle.Start - 500);
+		var rs = Math.round(rsX*10) / 10;
+		return rs;	
+	},
+	
+	getLabel : function (rs){
+		var rsMin = 5;
+		var rsMax = 35;
+		var rating;
+		if (rs < rsMin && rs>0)   rating = "TOO SLOW!";
+		else if (rs < 10 && rs>0) rating = "Slow, acceptable.";
+		else if (rs < 13 && rs>0) rating = "A bit slow.";
+		else if (rs < 15 && rs>0) rating = "Good.";
+		else if (rs < 23 && rs>0) rating = "Perfect.";
+		else if (rs < 27 && rs>0) rating = "Good.";
+		else if (rs < 31 && rs>0) rating = "A bit fast.";
+		else if (rs < rsMax && rs>0) rating = "Fast, acceptable.";
+		else              rating = "TOO FAST!";
+		return rating;
+	},
+	CalculateDurLavie : function(CurrentSub){
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + CurrentSub.StrippedText.length / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+		return durLavie;
+	
+	},
+	CalculateDisplaySpeed : function(CurrentSub){
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		return ds;
+	}
+}

obsolete/TOO_SLOW.js

+// too slow
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'TOO SLOW subtitles',
+  Description : 'Detects and fixes slow subtitles',
+  Color : 0xE7B8FF,
+  Message : 'Speed :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamLevel : { Value : 1, Unit : '1/2/3', Description: 'Level 1 = TOO SLOW\nLevel 2 = TOO SLOW + "Slow, acceptable"\nLevel 3 = TOO SLOW + "Slow, acceptable" + "A bit slow"' },
+ 
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+	// current length, duration
+    var len = CurrentSub.StrippedText.length;
+    var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+    var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+    // display speed
+    var dsMin = 4;
+    var dsMax = 22;
+    var dsX = len * 1000 / durMS;       // exact
+    var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+    // reading speed
+    var rsMin = 5;
+    var rsMax = 35;
+    var rsX = len * 1000 / (durMS - 500);
+    var rs = Math.round(rsX*10) / 10;
+    // rating
+    var rating;
+    if (rs < rsMin)   rating = "TOO SLOW!";
+    else if (rs < 10) rating = "Slow, acceptable.";
+    else if (rs < 13) rating = "A bit slow.";
+    else if (rs < 15) rating = "Good.";
+    else if (rs < 23) rating = "Perfect.";
+    else if (rs < 27) rating = "Good.";
+    else if (rs < 31) rating = "A bit fast.";
+    else if (rs < 35) rating = "Fast, acceptable.";
+    else              rating = "TOO FAST!";
+
+	// compute Lavie duration
+    var ParamIdealReadingSpeed = 20;
+    var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+    durLavie = Math.round(durLavie*10) / 10;
+
+	//level
+	switch(this.ParamLevel.Value){
+		//3 = TOO SLOW + "Slow, acceptable" + "A bit slow"
+		case 3:
+			if (rs < 13) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//2 = TOO SLOW + "Slow, acceptable"
+		case 2:
+			if (rs < 10) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			}
+			else {
+				return '';
+			}
+		//1 = TOO SLOW
+		default:
+			if (rs < rsMin) {
+				return (rating+' - '+dur + ' s (ideal : ' + durLavie+')');
+			} else {
+				return '';
+			}
+		break;
+	}
+
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + len / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		while(dur > durLavie && durMS > VSSCore.MinimumDuration){
+			CurrentSub.Stop --; 	
+			durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+			dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		}
+	}
+}

obsolete/TYPO_english_typo_nathbot.js

+// English typography
+// by Nathbot
+
+var DebugMode = false;
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'TYPO - English typography',
+  Description : 'Check text against english typography rules.',
+  Color : 0x25737D,
+  Message : 'Subtitle has typo :',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamAuthorizeHyphens : { Value : 0, Unit : '0/1', Description: '0 = Do not authorize double-hyphens as interruption sign - 1 = Authorize double-hyphens' },
+  
+  // We use a table of rules to define the typography
+  // Each rule is defined by those field :
+  //   - re : a regular expression
+  //   - msg : a message to display when the text match
+  //   - replaceby (optional) : a replace expression use to fix the error
+  //   - exception (optional) : if set to true the processing will stop on
+  //     this rule and no replacement will be made (msg can be used for debugging)
+	Rules : new Array(
+		{ re : /[ \f\t\u00A0\u2028\u2029]{2,}/mg, msg : "Pas plus d'un espace cons�cutif", replaceby: " "},
+		{ re : /[ \f\t\u00A0\u2028\u2029]+([\r\n])/mg, msg : "Pas d'espace avant une nouvelle ligne", replaceby: "$1"},
+		{ re : /([\r\n])[ \f\t\u00A0\u2028\u2029]+/mg, msg : "Pas d'espace apr�s une nouvelle ligne", replaceby: "$1"},
+		{ re : /([^-])\s+([.,?!:])/mg, msg : "Pas d'espace avant '.', ',', '?', ':' ou '!'", replaceby: "$1$2"},
+		{ re : /^-(\S)/mg, msg : "Un espace apr�s un '-' en d�but de ligne", replaceby: "- $1"},
+		{name:"apostrophe", re : /(\s'\s)|(\s')(?!em|cause|Cause|coz|Coz)|('\s)/mg, msg : "Pas d\'espace avant et apr�s une apostrophe", replaceby: "'"},
+		{ re : /^\.\.([^.])/mg, msg : "Signe de ponctuation invalide '..' (1)", replaceby: "... $1"},
+		{ re : /([^.])\.\.([^.])/mg, msg : "Signe de ponctuation invalide '..' (2)", replaceby: "$1...$2"},
+		{ re : /([^.])\.\.$/mg, msg : "Signe de ponctuation invalide '..' (3)", replaceby: "$1..."},
+		{ re : /\.{4,}(\b|\s)/mg, msg : "Points de suspension en trop", replaceby: '... '},		
+		{ re : /(�)/mg, msg : "Points de suspension en un seul caract�re", replaceby: "..."},
+		{ re : /([^\.])\.{3}(<\/i>){0,1}\b/mg, msg : "Un espace apr�s '...'", replaceby: "$1...$2 "},		
+		{ re : /^\.{3}\b/mg, msg : "Pas d'espace apr�s '...' en d�but de ligne", replaceby: '... '},		
+		{ re : /(http:\/\/[^\s\)]+)/mg, msg : "Ignorer les point dans les URL (1)", replaceby: "[url1=$1]", exception: true, },
+		{ re : /(www.[^\s)]+)/mg, msg : "Ignorer les points dans les URL (2)", replaceby: "[url2=$1]", exception: true},
+		{ re : /\b(([A-Z]\.){2,})\B/mg, msg : "Ignorer les points dans les acronymes", replaceby: "[acro=$1]", exception: true},
+		//{ re : /([0-9]+[.,])\s+([0-9]+)/mg, msg : "Pas d'espace dans un nombre", replaceby: "$1$2"}, // fonctionne pas pour : "50, 75 kg � peu pr�s."
+		{ re : /(\b)(Ok|ok)(\b)/mg, msg : "OK must be uppercase", replaceby: "$1OK$3"},
+		{ re : /(�)/mg, msg : "Curly quote --> Regular", replaceby: "'"},
+		{ re : /[A-Z]{2,}[a-z]{2,}/mg, msg : "Erreur de majuscule"},
+		{ re : /([0-9]+[.,][0-9]+)/mg, msg : "Ignorer points et virgules dans les nombres", replaceby: "[nombre=$1]", exception: true},
+		{ re : /([\.,])([A-Za-z]+)/mg, msg : "Un espace apr�s un '.' ou une ','", replaceby: "$1 $2"},
+		{ re : /--/mg, msg : "Signe d'interruption '--' doit �tre '...'", replaceby: "..."}
+	),
+	
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+  	var SubText = CurrentSub.Text;
+  	if(this.ParamAuthorizeHyphens.Value == 0) var _max = this.Rules.length;
+  	else var _max = this.Rules.length-1;
+  	
+  	for(i=0; i < _max; i++) {
+  		if(this.Rules[i].re.test(SubText)) {
+  			if(DebugMode && this.Rules[i].replaceby != null) {
+  				ScriptLog(SubText.replace(this.Rules[i].re, this.Rules[i].replaceby));
+  				ScriptLog('');
+  			} 			
+  			return (this.Rules[i].exception) ? '' : this.Rules[i].msg;
+  		}
+  	}
+  	return '';
+  },
+  
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+  	var SubText = CurrentSub.Text;
+  	var exception = 0;
+  	if(this.ParamAuthorizeHyphens.Value == 0) var _max = this.Rules.length;
+  	else var _max = this.Rules.length-1;
+
+  	for(i=0; i < _max; i++) {
+  		if((this.Rules[i].replaceby != null) && (this.Rules[i].re.test(SubText))) {
+  		  //exception for apostrophe rule...
+  		  if(this.Rules[i].name != undefined && this.Rules[i].name == "apostrophe"){
+			var exc_regex = /([sn]'\s)/mg;
+			if(exc_regex.test(SubText)){
+				exception = 1;
+			}
+  		  }
+  		  if(!this.Rules[i].exception && this.Rules[i].replaceby != undefined && exception == 0) {
+				  CurrentSub.Text = SubText.replace(this.Rules[i].re, this.Rules[i].replaceby);
+				}
+  			return;
+  		}
+  	}
+  }
+}

obsolete/all_to.js

+// All to...
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'All to...',
+  Description : 'Sets all subs to the specified level',
+  Color : 0x000000,
+  Message : 'All to...',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamLevel : { Value : 'FA', Unit : 'TF/FA/ABF', Description: 'TF=TOO FAST, FA=Fast acceptable, ABF=A bit fast'},
+
+  Labels : {FA: "Fast, acceptable.", TF: "TOO FAST!", ABF: "A bit fast."},
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    var rs = this.CalculateRS(CurrentSub);
+    
+    
+    switch(this.ParamLevel.Value){
+      case 'TF':
+        if(rs < 35 && this.getLabel(rs) != "TOO FAST!")
+          return this.Labels[this.ParamLevel.Value]+" - Current speed is: "+this.getLabel(rs);
+        else
+          return '';
+      break;
+      case 'FA':
+        if(rs < 31 && this.getLabel(rs) != "TOO FAST!" && this.getLabel(rs) != "Fast, acceptable.")
+          return this.Labels[this.ParamLevel.Value]+" - Current speed is: "+this.getLabel(rs);
+        else
+          return '';
+      break;
+      case 'ABF':
+        if(rs < 27 && this.getLabel(rs) != "TOO FAST!" && this.getLabel(rs) != "Fast, acceptable." && this.getLabel(rs) != "A bit fast.")
+          return this.Labels[this.ParamLevel.Value]+" - Current speed is: "+this.getLabel(rs);
+        else
+          return '';
+      break;
+       default:
+        return '';
+      break;
+    }
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+    var durMS = CurrentSub.Stop - CurrentSub.Start;
+    var rs = this.CalculateRS(CurrentSub);
+    while(this.getLabel(rs) != this.Labels[this.ParamLevel.Value] && durMS > VSSCore.MinimumDuration){
+      CurrentSub.Stop --; 	
+      durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+      rs = this.CalculateRS(CurrentSub);
+    }
+  },
+
+
+
+	CalculateRS : function (Subtitle){
+		var durMS = Subtitle.Stop - Subtitle.Start;
+		var rsX = Subtitle.StrippedText.length * 1000 / (Subtitle.Stop - Subtitle.Start - 500);
+		var rs = Math.round(rsX*10) / 10;
+		return rs;	
+	},
+	
+	getLabel : function (rs){
+		var rsMin = 5;
+		var rsMax = 35;
+		var rating;
+		if (rs < rsMin && rs>0)   rating = "TOO SLOW!";
+		else if (rs < 10 && rs>0) rating = "Slow, acceptable.";
+		else if (rs < 13 && rs>0) rating = "A bit slow.";
+		else if (rs < 15 && rs>0) rating = "Good.";
+		else if (rs < 23 && rs>0) rating = "Perfect.";
+		else if (rs < 27 && rs>0) rating = "Good.";
+		else if (rs < 31 && rs>0) rating = "A bit fast.";
+		else if (rs < rsMax && rs>0) rating = "Fast, acceptable.";
+		else              rating = "TOO FAST!";
+		return rating;
+	},
+	CalculateDurLavie : function(CurrentSub){
+		var ParamIdealReadingSpeed = 20;
+		var durLavie = 0.5 + CurrentSub.StrippedText.length / ParamIdealReadingSpeed;
+		durLavie = Math.round(durLavie*10) / 10;
+		return durLavie;
+	
+	},
+	CalculateDisplaySpeed : function(CurrentSub){
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		return ds;
+	}
+
+}

obsolete/cps_too_low.js

+// Original plugin = Too long display time
+// (christophe.paris <at> free.fr)
+//
+// extended by Nathbot and renamed "CPS too low"
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'CPS too low',
+  Description : 'Detects and fixes subtitles when the CPS is strictly inferior to the specified value.',
+  Color : 0xAF6DFF, 
+  Message : 'CPS is too low:',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMinCPS : { Value : 4, Unit : 'Char/s', Description: 'Minimum CPS allowed' },
+  ParamIgnoreLinesOf : { Value : 0, Unit : 'Characters', Description: 'Ignore the subtitles that have lines with less than ## characters' },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.
+  // Otherwise return an empty string.
+  // Don't forget that PreviousSub and NextSub can be null
+  HasError : function(CurrentSub, PreviousSub, NextSub) {
+    // Ignore lines with length < to this.ParamIgnoreLinesOf.Value
+    if(CurrentSub.StrippedText.length < this.ParamIgnoreLinesOf.Value)
+    {
+        return '';
+    }
+    
+    Duration = CurrentSub.Stop - CurrentSub.Start;
+    CharPerSec = (CurrentSub.StrippedText.length * 1000) / Duration;
+    if (CharPerSec < this.ParamMinCPS.Value) {
+    	return (Math.round(CharPerSec) + ' ' + this.ParamMinCPS.Unit);
+    } else {
+    	return '';
+    }
+  },
+
+
+
+  FixError : function(CurrentSub, PreviousSub, NextSub) {
+		// current length, duration
+		var len = CurrentSub.StrippedText.length;
+		var durMS = CurrentSub.Stop - CurrentSub.Start;     // in milliseconds
+		var dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		// display speed
+		var dsMin = 4;
+		var dsMax = 22;
+		var dsX = len * 1000 / durMS;       // exact
+		var ds = Math.round(dsX*10) / 10;   // rounded to 1 decimal digit
+		// reading speed
+		var rsMin = 5;
+		var rsMax = 35;
+		var rsX = len * 1000 / (durMS - 500);
+		var rs = Math.round(rsX*10) / 10;
+		// compute Lavie duration
+		var durLavie = 0.5 + len / VSSCore.CpsTarget;
+		durLavie = Math.round(durLavie*10) / 10;
+
+		while(dur > durLavie 
+			  && (durMS) > VSSCore.MinimumDuration){
+			CurrentSub.Stop -=1; 	
+			durMS = CurrentSub.Stop - CurrentSub.Start; // in milliseconds
+			dur = Math.round(durMS/100) / 10; // in seconds, rounded to 1 decimal digit
+		}
+  }
+}

obsolete/extend_CPS.js

+// Extend CPS
+// by Nathbot
+
+VSSPlugin = {
+  // ----- Plugin constant -----
+  Name : 'Extend CPS 2',
+  Description : 'An error is detected when the number of Char/s is strictly '+
+  	'superior to the specified value. The fixer will extend the duration of the subtitle without overlapping the next one.',
+  Color : 0xC91191,
+  Message : 'Subtitle CPS is too fast:',
+
+  // ----- Plugin parameters available from VSS GUI (name must start with "Param") -----
+  ParamMaxCPS : { Value : 25, Unit : 'Char/s' },
+  ParamMaxStartMove : { Value : 250, Unit : 'ms', Description : 'Maximum delay of the subtitle start if there is not enough space to delay the subtitle end'  },
+
+  // ----- HasError method called for each subtitle during the error checking -----
+  // If there is an error on CurrentSub return a string containing the error description.